我有一个简单的基类和两个继承它的类。问题是没有使用每个子类中的移动赋值运算符。这基本上就是我所拥有的:
class Parent {
public:
virtual ~Parent();
virtual Parent& operator=(Parent &&parent);
};
class Child1 : public Parent {
public:
~Child1();
Child1& operator=(Child1 &&child);
};
class Child2 : public Parent {
public:
~Child2();
Child2& operator=(Child2 &&child);
};
这些实现充满了日志,因此我知道被调用的内容以及何时调用。然后,我运行这个(伪)代码:
Parent &p {};
if (x == 1)
p = Child1 {};
else
p = Child2 {};
我得到的输出看起来像这样:
: Child constructor
: Parent move operator
: Child destruct
: SIGSEGV
知道我做错了吗?
答案 0 :(得分:3)
这是slicing的经典案例,您将派生类型的实例分配给基本类型的实例。要解决这个问题,你必须使用动态分配和指针:
std::unique_ptr<Parent> p;
if(x == 1)
p = std::make_unique<Child1>();
else
p = std::make_unique<Child2>();
答案 1 :(得分:2)
C ++不会这样做。您不能仅仅将子类对象分配给基类对象并希望它能够工作;这个错误被称为&#34;对象切片&#34;。
此外,您的if语句的条件不是比较,而是它的分配。
答案 2 :(得分:1)
您在以下情况下重载operator=
:(伪代码)
Parent = Parent&&
Child1 = Child1&&
Child2 = Child2&&
然而,您的代码会尝试执行Parent = Child1
,这不是其中一个选项。请注意,左侧是定义函数的类类型 - 返回值类型不会影响函数重载。
在C ++中永远不会从基类到派生类的隐式转换,因为这太危险了。 (您必须使用强制转换来请求该行为)。例如,在这种情况下,将Parent
作为参数传递给期望Child1
的函数是错误的,因为父级不是Child1。
但是,存在从派生类到基类引用的隐式转换。因此Parent = Child1
将匹配Parent = Parent&&
。它不能与其他任何一个匹配,因为左侧没有隐式转换为派生类。
要解决此问题,您的选择包括:
Parent = Child1&&
内明确定义Parent = Child2&&
和Parent
(这需要转发声明)Parent = Parent&&
使用tag-dispatching或dynamic_cast
或其他方式,以实现所有子类的所需行为正如其他人所提到的,也许你的设计需要重新思考,因为你正在故意切片,但很少有切片是面向对象设计的预期部分。您可能希望Parent p;
实际上是父级的引用或指针,而不是实际的父级。