c++ - 我有一个向量,它具有指向通过接口访问的 2 个子类型的元素的指针。似乎无法重新排列矢量
问题描述
我正在为学校设计一个真正过度设计的矩阵计算器,并用我需要的最后一个功能撞到了一堵砖墙。的完整版本transpose()
应该重新排列我的矩阵并切换列和行。
我之前用一个片段发布了这个问题,但被要求写一个最低限度的可重现样本。这不是很“最低限度”,但我试过了。
所以。我有一个std::vector<std::unique_ptr<Interface>>
可以容纳类型Sub1
和Sub2
.
在完整版中,我有一个类可以绕过Interface
并且工作正常,因为它只包含Sub2
对象。
但是,当向量中有多种类型时,我似乎无法让它工作。在过去的几个小时里我尝试过的任何事情都没有做任何事情。
#include <iostream>
#include "main.h"
#include <memory>
#include <utility>
#include <vector>
#include <sstream>
//this is the one that won't work
Super Super::transpose() const {
Super newMatrix = *this;
int i = 1;
for(auto& elem : elements){
*elem = *newMatrix.elements[i];
i--;
}
return *this;
}
int main() {
std::vector<std::unique_ptr<Interface>> newMatrix;
newMatrix.push_back(std::unique_ptr<Sub1>(new Sub1('x')));
newMatrix.push_back(std::unique_ptr<Sub2>(new Sub2(1)));
Super mtx(std::move(newMatrix),2 );
std::cout << mtx << std::endl;
mtx.transpose();
std::cout << mtx;
return 0;
}
//busywork from here on
Super::Super(std::vector<std::unique_ptr<Interface>> matrix, int pN){
elements = std::move(matrix);
n = pN;
}
std::unique_ptr<Interface> Sub1::clone() const {
char newVal = val;
return std::unique_ptr<Sub1>(new Sub1(newVal));
}
std::unique_ptr<Interface> Sub2::clone() const {
int newVal = i;
return std::unique_ptr<Sub2>(new Sub2(newVal));
}
Sub1::Sub1(char pVal) {
val = pVal;
}
Sub2::Sub2(int pI) {
i = pI;
}
std::string Sub1::toString() const {
std::stringstream ss;
ss << val;
return ss.str();
}
std::string Sub2::toString() const {
std::stringstream ss;
ss << i;
return ss.str();
}
std::ostream &operator<<(std::ostream &os, const Super &matrix) {
os << "[";
int i = 0;
for (auto &elem : matrix.elements) {
os << elem->toString();
if (i < matrix.n - 1) {
os << ",";
}
i++;
}
os << "]";
return os;
}
Super::Super(const Super &matrix) {
n = matrix.n;
for (auto &elem : matrix.elements) {
std::unique_ptr<Interface> newElem = elem->clone();
elements.push_back(std::move(newElem));
}
}
这是标题
#ifndef EXAMPLE_MAIN_H
#define EXAMPLE_MAIN_H
#include <memory>
#include <vector>
class Interface{
public:
virtual ~Interface() = default;
virtual std::unique_ptr<Interface> clone() const = 0;
virtual std::string toString() const = 0;
};
class Super{
private:
std::vector<std::unique_ptr<Interface>> elements;
int n = 2;
public:
Super(std::vector<std::unique_ptr<Interface>> elements, int n);
Super(const Super &matrix);
Super transpose() const;
friend std::ostream &operator<<(std::ostream &os, const Super &matrix);
};
class Sub1: public Interface{
private:
char val;
public:
Sub1(char pVal);
std::string toString() const override;
std::unique_ptr<Interface> clone() const override;
};
class Sub2: public Interface{
private:
int i;
public:
Sub2(int pI);
std::string toString() const override;
std::unique_ptr<Interface> clone() const override;
};
std::ostream &operator<<(std::ostream &os, const Super &matrix);
#endif //EXAMPLE_MAIN_H
解决方案
Super Super::transpose() const;
这看起来像一个函数,*this
在调用时不应更改,但应返回*this
.
例子:
#include <algorithm>
Super Super::transpose() const {
Super newMatrix = *this;
std::reverse(newMatrix.elements.begin(), newMatrix.elements.end());
return newMatrix;
}
如果您想*this
就地转置,请将其更改为:
Super& Super::transpose();
Super& Super::transpose() {
std::reverse(elements.begin(), elements.end());
return *this;
}
如果必须先创建一个临时对象,则可以,但不能将 dereferenced 分配Interface*
给另一个 dereferenced Interface*
。虽然移动unique_ptr
作品:
Super& Super::transpose() {
Super newMatrix = *this;
size_t s = elements.size();
for(size_t i = 0; i < s; ++i) {
elements[i] = std::move(newMatrix.elements[s - i - 1]);
}
return *this;
}
您还可以将 封装std::unique_ptr<Interface>
在包装类中以添加复制构造函数和赋值运算符(不支持std::unique_ptr
)。通过这样做,您可以大大简化您的其他类。你的Super
班级不需要知道任何关于克隆的知识。复制/移动元素可以开箱即用。
示例包装器:
class Cell {
public:
Cell() noexcept = default; // empty Cell ctor
explicit Cell(std::unique_ptr<Interface>&& d) noexcept; // converting ctor
// rule of five
Cell(const Cell& rhs); // must be implemented
Cell(Cell&& rhs) noexcept = default; // handled by unique_ptr
Cell& operator=(const Cell& rhs); // must be implemented
Cell& operator=(Cell&& rhs) noexcept = default; // handled by unique_ptr
~Cell() = default; // handled by unique_ptr
explicit operator bool() const noexcept; // proxy for unique_ptr operator bool
void reset() noexcept; // empty the Cell
// dereferencing
Interface& operator*();
const Interface& operator*() const;
Interface* operator->();
const Interface* operator->() const;
std::ostream& print(std::ostream& os) const; // calls: os << data->toString()
// A helper factory to make a Cell of a certain type using the converting ctor
template<typename T, class... Args>
static Cell make(Args&&... args) {
return Cell(std::make_unique<T>(std::forward<Args>(args)...));
}
private:
std::unique_ptr<Interface> data{};
};
std::ostream& operator<<(std::ostream& os, const Cell& c); // calls c.print(os)
复制构造函数和复制赋值运算符可以这样实现:
Cell::Cell(const Cell& rhs) : data(rhs ? rhs.data->clone() : nullptr) {}
Cell& Cell::operator=(const Cell& rhs) {
if(this != &rhs) data = rhs ? rhs.data->clone() : nullptr;
return *this;
}
这是一个使用std::vector<std::vector<Cell>>
. 这样的 2D 矢量不是很有效,但它可以用于演示的目的。
推荐阅读
- c++ - vcpkg 中的“找不到完整的工具集”错误
- javascript - 在保持动画顺序的同时动态添加 v-tab-item
- laravel - 订阅者中间件路由允许公众查看所有受限页面
- android - 使用数据绑定从布局中解耦的 RecyclerViewAdapter
- powershell - Powershell JiraPS - 使用 Get-JiraIssueAttachmentFile 下载附件仅返回 true 但没有文件
- prolog - 使用“或”运算符和使用多个子句有什么区别吗?
- c# - C# Nuget 包输出位置建议
- rsocket - 第 3 个消息帧的 RSocket Net,pipereader.ReadAsync 被截断,导致 MessageFramePeek 方法出错
- ubuntu - 为什么 sudo 命令后会出现“[sudo]”?
- node.js - 类验证器:使用类成员作为装饰器参数