继承构造函数与转发引用:Base/Derived构造调用差异原因探究
为何Base与Derived的构造函数调用行为存在差异?
先看两个结构体定义:
struct Base { Base() = default; Base(auto&&); }; struct Derived : Base { using Base::Base; };
当分别将Type指定为Base和Derived时,执行以下测试代码会得到不同的构造函数调用结果:
Type t; const Type ct; Type t1 = t; Type t2 = ct; Type t3 = std::move(t); Type t4 = std::move(ct);
测试结果对比
Type = Base | Type = Derived | |
|---|---|---|
t1 | 调用转发引用构造函数 | 调用拷贝构造函数 |
t2 | 调用拷贝构造函数 | 调用拷贝构造函数 |
t3 | 调用移动构造函数 | 调用移动构造函数 |
t4 | 调用转发引用构造函数 | 调用拷贝构造函数 |
差异原因解析
核心差异来自重载决议的优先级规则,以及基类/派生类中合成构造函数与模板构造函数的交互:
1. Base类的构造函数匹配逻辑
Base类中,用户声明的是模板构造函数(Base(auto&&)),而模板构造函数不会阻止编译器生成合成的非模板拷贝构造函数(Base(const Base&))和移动构造函数(Base(Base&&))。
t1 = t(非const左值Base):
候选函数包括模板实例化的Base(Base&)(完全匹配非const左值)和合成的Base(const Base&)(需要隐式转换为const引用)。由于前者匹配度更高,因此调用转发引用构造函数。t4 = std::move(ct)(const右值Base):
候选函数包括模板实例化的Base(const Base&&)(完全匹配const右值)和合成的Base(const Base&)(需要将右值转换为左值引用),而合成的移动构造函数Base(Base&&)不匹配const右值。因此匹配度更高的转发引用构造函数被选中。
2. Derived类的构造函数匹配逻辑
Derived通过using Base::Base;继承了Base的所有构造函数(包括模板构造函数),但编译器会为Derived合成非模板的拷贝构造函数(Derived(const Derived&))和移动构造函数(Derived(Derived&&))——因为Derived没有显式声明这些构造函数。
这里的关键规则是:重载决议中,非模板函数的优先级高于模板函数的特化版本。
t1 = t(非const左值Derived):
候选函数包括继承的模板实例化Derived(Derived&)和合成的非模板拷贝构造函数Derived(const Derived&)。尽管前者匹配度略高,但非模板函数优先级更高,因此调用拷贝构造函数。t4 = std::move(ct)(const右值Derived):
候选函数包括继承的模板实例化Derived(const Derived&&)和合成的非模板拷贝构造函数Derived(const Derived&)。同样,非模板函数优先级更高,因此调用拷贝构造函数。
补充:t2与t3行为一致的原因
t2是const左值:无论Base还是Derived,合成的拷贝构造函数const Type&都是最优匹配(Base中模板实例化的签名与合成拷贝构造函数完全一致,此时非模板函数优先)。t3是非const右值:合成的移动构造函数Type(Type&&)是匹配度最高的非模板函数,因此优先被选中。
内容的提问来源于stack exchange,提问作者Dr. Gut
相关产品推荐
相关产品推荐

