如何从基类调用派生赋值运算符?

How to call derived assignment operator from base class?

提问人:Sideshow Bob 提问时间:3/23/2016 最后编辑:CommunitySideshow Bob 更新时间:3/24/2016 访问量:1579

问:

给定一个指向抽象基类的指针,我想复制或赋值它(作为基类)并调用派生的复制构造函数或赋值运算符。我知道复制构造函数不能是虚拟的,所以大概复制构造函数不是执行此操作的选项,但赋值运算符是。不过,它似乎不起作用:以下代码打印A*

assigned a
x!
destroyed b
destroyed b

无法分配 B。

#include <iostream>
using namespace std;

class A
{
public:
    virtual void x()=0;
    virtual ~A() {}
    virtual A& operator=(const A& other) { cout << "assigned a" << endl; return *this;}
};

class B : public A
{
public:
    virtual B& operator=(const B& other)  { cout << "assigned b" << endl; return *this;}
    virtual void x() { cout << "x!" << endl; }
    virtual ~B() { cout << "destroyed b" << endl; }
};

int main() 
{ 
    A* a = new B(); 
    A* aa = new B(); 
    *aa=*a; 
    aa->x(); 
    delete a; 
    delete aa; 
    return 0;
}

如何做到这一点?

编辑 这个问题在下面得到了正确的回答,但这是错误的问题。我不应该尝试覆盖赋值运算符,因为我不希望 A 的子类相互赋值。有关更简单的答案(希望如此),请参阅 C++ 通过调用基类优雅地克隆派生类

C++ 继承 赋值运算符

评论

0赞 Pete Becker 3/23/2016
这并不重要,但这个问题询问的是虚拟基类,而代码没有虚拟基类
0赞 molbdnilo 3/23/2016
我认为你的意思是抽象基类,而不是“虚拟”(这是完全不同的东西)。基类的抽象性与您的问题无关。

答:

4赞 vsoftco 3/23/2016 #1

问题是 ur 没有覆盖 中的那个。将其更改为B::operator=A

virtual A& operator=(const A& other)  { cout << "assigned b" << endl; return *this;}

它会起作用的。此外,在重写成员函数时尝试使用 override 关键字(需要 C++11)。如果不重写,代码将无法编译。就您而言,它会发现您的错误

错误:“虚拟 B& B::operator=(const B&)”标记为“覆盖”,但不覆盖

PS:您可能正在考虑协变返回类型。为了使其正常工作,函数的签名必须相同,但返回类型除外。例如,这将起作用:

virtual B& operator=(const A& other)  { cout << "assigned b" << endl; return *this;}

评论

0赞 Sideshow Bob 3/23/2016
好的,这很好,但是如果它不能保证它是 的实例,如何访问唯一的字段?B::operator=Bconst A& otherB
0赞 vsoftco 3/23/2016
@SideshowBob 您可以测试dynamic_cast的结果,看看是否真的是 .但这也应该让你思考你的设计是否合理。otherB
0赞 Sideshow Bob 3/23/2016
这确实很难,这让我质疑我的设计。最终,我需要从基类指针深层复制一个类,而不知道该类到底是什么。根据封装原则,这不是一个疯狂的要求,对吧?
1赞 vsoftco 3/23/2016
@SideshowBob 一种解决方案是通过不同的函数使用双重调度,称为 。assign
0赞 Sideshow Bob 3/23/2016
这意味着当只有一个派生类需要默认值以外的任何内容时,为所有派生类提供一个函数(或者在我的情况下可以完成这项工作)。有没有办法说?assignclonefind the derived class assignment operator (which will be virtual if not default) and use it