为何C++派生类的默认构造函数会被删除?代码示例解析
首先先贴出触发错误的代码:
template<typename T> class Foo { T tVar; public: Foo(T t) : tVar(t) {} }; class FooDerived : public Foo<std::string> {}; int main() { FooDerived d; // 此处触发编译错误 return 0; }
错误根源:C++构造函数的生成规则与继承逻辑
我们一步步拆解这个问题的本质:
基类
Foo丢失了默认构造函数
C++编译器的规则是:如果一个类定义了任意用户自定义的构造函数(这里是带参数的Foo(T t)),编译器就不会再自动为这个类生成默认构造函数(即无参的Foo())。所以Foo<std::string>作为Foo的实例化类,是没有默认构造函数的。派生类默认构造函数的生成依赖基类
对于FooDerived这种没有定义任何构造函数的类,编译器本来会自动生成一个默认构造函数。但这个自动生成的构造函数有个硬性要求:必须调用基类的默认构造函数,来完成基类部分的初始化工作。无法完成初始化,导致派生类默认构造函数被标记为删除
因为基类Foo<std::string>没有可用的默认构造函数,编译器找不到合法的基类构造函数来完成派生类对象的初始化流程。这时编译器不仅无法生成有效的默认构造函数,还会把FooDerived的默认构造函数标记为删除的函数(deleted function)。当你在main里尝试创建FooDerived d;时,自然就触发了"无法引用已删除函数"的错误。
为什么添加基类默认构造函数就能解决问题?
当你给基类Foo补充一个默认构造函数(比如Foo() = default;或者手动实现一个无参构造),Foo<std::string>就拥有了合法的默认构造函数。此时编译器可以正常为FooDerived生成默认构造函数:这个自动生成的构造函数会调用基类的默认构造函数,完成基类部分的初始化,而派生类自身没有额外成员需要处理,整个对象就能正常创建了。
补充:另一种可行的解决思路
除了给基类加默认构造函数,你也可以在派生类中自定义构造函数,显式调用基类的带参构造函数,比如:
class FooDerived : public Foo<std::string> { public: FooDerived() : Foo<std::string>("default_value") {} };
这样也能绕过错误——因为你自己提供的构造函数已经明确指定了如何初始化基类,编译器不需要再尝试生成默认构造函数。
内容的提问来源于stack exchange,提问作者bencemeszaros

