You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

继承构造函数与转发引用: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 = BaseType = 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:51:03