【问题标题】:Move assignment operator in subclass not being called / inherited未调用/继承子类中的移动赋值运算符
【发布时间】:2015-11-10 00:35:09
【问题描述】:

我有一个简单的基类和两个继承自它的类。问题是没有使用每个子类中的移动赋值运算符。这基本上是我所拥有的:

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

知道我做错了什么吗?

【问题讨论】:

标签: c++ c++11


【解决方案1】:

这是slicing 的经典案例,您将派生类型的实例分配给基类型的实例。要解决这个问题,您必须使用动态分配和指针:

std::unique_ptr<Parent> p;

if(x == 1)
  p = std::make_unique<Child1>();
else
  p = std::make_unique<Child2>();

【讨论】:

  • 谢谢 - 还在学习这个。不幸的是,我无法使用 std::make_unique 。 (我正在使用 Xcode 编译以支持跨平台:MacOSX、iOS、Android 通过 JNI 等)还有其他方法吗?
  • 不幸的是,我并不熟悉所有这些平台。如果他们没有 C++11,那么他们可能也没有 Boost,所以原始的 new/delete 可能是唯一的选择。那或者你可以滚动你自己的智能指针来处理内存管理。
  • @cetcet 是 p.reset( new Child1 );
  • @ChrisHayden std::make_unique 在 c++11 中不可用,仅在 c++14 中可用
  • @Slava 你是对的!希望@cetcet 有 C++11,他仍然可以使用unique_ptr
【解决方案2】:

C++ 不是这样工作的。您不能只将子类对象分配给基类对象并期望它起作用;这个错误被称为“对象切片”。

另外,你的 if 语句的条件不是比较,而是赋值。

【讨论】:

  • if 语句是一个错字(这里不是我的代码);它已被修复。
【解决方案3】:

对于以下情况,您已经重载了operator=:(伪代码)

Parent = Parent&&
Child1 = Child1&&
Child2 = Child2&&

但是,您的代码随后会尝试执行 Parent = Child1,这不是这些选项之一。注意左边是定义函数的类类型——返回值类型不影响函数重载。

在 C++ 中从不存在从基类到派生类的隐式转换,因为那太危险了。 (您必须使用强制转换来请求该行为)。例如,在这种情况下,将 Parent 作为参数传递给期望 Child1 的函数是错误的,因为该 Parent 不是 Child1。

但是,存在从派生类到基类引用的隐式转换。所以Parent = Child1 将匹配Parent = Parent&amp;&amp;。它不能匹配任何其他的,因为左侧没有隐式转换为派生类。

要解决这个问题,您的选择包括:

  • Parent 内显式定义Parent = Child1&amp;&amp;Parent = Child2&amp;&amp;(这需要前向声明)
  • Parent = Parent&amp;&amp; 使用标记调度或dynamic_cast 或其他方式,以实现所有子类的所需行为

正如其他人所提到的,也许您的设计需要重新考虑,因为您在这里是有意进行切片的,但是切片很少是面向对象设计的预期部分。可能您希望 Parent p; 实际上是对 Parent 的引用或指针,而不是实际的 Parent。

【讨论】:

  • 感谢您的回复。我不想转换任何东西。我想我的错误是没有使用引用和/或指针。
猜你喜欢
  • 2018-11-24
  • 2020-12-15
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
  • 1970-01-01
  • 2015-02-09
  • 2012-02-12
  • 2021-08-28
相关资源
最近更新 更多