为何从基类赋值运算符调用时,派生类默认赋值运算符未被触发?
抽象基类派生类赋值运算符的编译错误分析
问题场景
当实现继承自抽象基类的派生类时,通过基类到派生类的赋值运算符中用dynamic_cast调用派生类赋值运算符,手动实现派生类的拷贝赋值运算符时代码可正常运行:
#include <iostream> using namespace std; class base { public: virtual base& operator = (const base& ) = 0; }; class derived: public base { public: derived (int d): data(d) {}; derived& operator = (const base& b) { if (&b == this) return *this; const derived &d = dynamic_cast<const derived&> (b); *this = d; return *this; } derived& operator = (const derived& d) { if (&d == this) return *this; data = d.data; return *this; } private: int data; };
但如果不显式实现derived& operator=(const derived&),或使用derived& operator=(const derived&) = default;,会触发编译错误:undefined reference to base::operator=(base const&),即尝试调用抽象方法。
错误原因
- 编译器生成的默认拷贝赋值运算符(或
=default显式要求生成的),会自动插入对基类拷贝赋值运算符的调用,以此完成基类部分的赋值操作。 - 基类
base中operator=是纯虚函数,仅声明了接口但没有提供具体实现,因此链接阶段无法找到该函数的定义,导致报错。 - 手动实现派生类拷贝赋值运算符时,未显式调用基类的
operator=,编译器也不会自动插入这个调用,因此不会触发对基类纯虚函数的调用,代码可正常运行。
解决方案:无需手动实现派生类赋值运算符的方法
给基类的纯虚operator=提供一个空实现即可。纯虚函数允许拥有具体实现,这样默认生成的派生类赋值运算符调用基类operator=时就有了合法的定义,同时派生类的默认赋值运算符会自动处理自身成员变量,无需手动编写。
修改后的基类代码:
class base { public: virtual base& operator = (const base& ) = 0; }; // 为纯虚赋值运算符提供空实现 base& base::operator=(const base&) { return *this; }
此时派生类可以直接使用默认生成的拷贝赋值运算符,或显式声明=default:
class derived: public base { public: derived (int d): data(d) {}; derived& operator = (const base& b) { if (&b == this) return *this; const derived &d = dynamic_cast<const derived&> (b); *this = d; return *this; } // 无需手动实现,使用默认版本 derived& operator = (const derived&) = default; private: int data; };
注意:
dynamic_cast<const derived&>如果转换失败会抛出std::bad_cast异常,若需要避免异常,可改用指针版本的dynamic_cast,通过判断指针是否为空来处理转换失败的情况。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

