关于隐式移动赋值运算符调用基类拷贝赋值运算符的规则确认
C++隐式移动操作的基类调用规则解析
示例代码
#include <string> struct Base { ~Base() = default; std::string strBase{ "Base"}; }; struct Derived : public Base { std::string strDerived{ "Derived" }; }; int main() { Derived a, b; a = std::move( b ); return 0; }
核心疑问
观察到示例中Derived的strDerived被移动,而基类Base的strBase被拷贝,需明确以下问题:
- 遵循零规则的
Derived的隐式声明移动赋值运算符,在基类Base无移动赋值运算符时,是否总会调用基类的隐式拷贝赋值运算符?是否有C++标准的明确保证? - 若将示例中的移动赋值替换为移动构造,情况是否相同?
标准规则与行为解释
1. 隐式移动赋值运算符的行为
根据C标准(C11及后续版本),当类的移动赋值运算符被隐式声明时:
- 对于基类子对象:如果基类没有可访问的、未被删除的移动赋值运算符,则会调用基类的隐式(或显式)拷贝赋值运算符。
示例中的Base因为声明了用户自定义析构函数(即使是=default),在C11中会导致隐式移动赋值运算符被删除;C17及以后虽放宽了规则,但Base仍未生成移动赋值运算符,因此Derived的隐式移动赋值会调用Base的拷贝赋值,导致strBase被拷贝。 - 对于派生类的非静态成员:如果成员类型有可访问的移动赋值运算符(如
std::string),则调用该成员的移动赋值,因此strDerived被移动。
这一行为是C++标准明确保证的。
2. 隐式移动构造函数的情况
替换为移动构造时,规则完全一致:
- 隐式移动构造函数会先初始化基类子对象:如果基类没有可访问的、未被删除的移动构造函数,则调用基类的拷贝构造函数。
- 派生类成员则会调用自身的移动构造函数(如
std::string的移动构造)。
因此移动构造场景下,同样会出现基类成员被拷贝、派生类成员被移动的现象,这也是标准规定的行为。
内容的提问来源于stack exchange,提问作者SoulfreezerXP
相关产品推荐
相关产品推荐

