如何在派生类中保留默认构造函数(无需显式添加Derived() = default;)
咱们先搞清楚为啥你的代码会编译失败:
当你在派生类Derived里声明了任何非模板构造函数(比如你写的explicit Derived(int) {}),C++编译器就不会自动为这个派生类生成默认构造函数了。而且根据标准规则,此时基类的默认构造函数也没法通过using Base::Base;继承到派生类中——因为只要派生类有自己的非模板构造函数,继承构造函数的逻辑就会跳过基类的默认构造函数。这就导致main里的Derived d;找不到可用的无参构造函数,直接报错。
那怎么在不写Derived() = default;的前提下解决这个问题呢?关键是要避免声明非模板构造函数,同时保留接受int参数的构造能力。这里有个实用的技巧:
用模板构造函数替代非模板构造函数
把你原来的explicit Derived(int) {}改成带类型约束的模板构造函数,这样既可以确保只接受int类型的参数,又不会阻止编译器自动生成默认构造函数。修改后的代码如下:
#include <type_traits> struct Base { Base() = default; }; struct Derived : Base { using Base::Base; // 模板构造函数+类型约束,仅接受int参数 template<typename T> explicit Derived(T) requires std::is_same_v<T, int> { // 这里可以写原来Derived(int)里的逻辑 } }; int main() { Derived d; // 现在编译正常了! Derived d2(1); // 依然可以正常初始化int参数的对象 // Derived d3(3.14); // 会编译错误,符合我们只接受int的预期 }
为什么这个方法有效?
C++标准里规定:只有用户声明的非模板构造函数才会阻止编译器生成默认构造函数。模板构造函数不属于这个范畴,所以编译器会自动为Derived生成默认构造函数,这个生成的构造函数会自动调用基类Base的默认构造函数,完美满足你的需求。
备选方案(局限性较大)
如果你不需要在Derived(int)里写复杂逻辑,也可以把这个构造函数移到一个单独的基类中,让Derived多重继承:
struct Base { Base() = default; }; struct IntHolder { explicit IntHolder(int) {} }; struct Derived : Base, IntHolder { using Base::Base; using IntHolder::IntHolder; };
不过这个方法有个明显的局限:IntHolder必须有默认构造函数,否则编译器生成的Derived默认构造函数会因为无法初始化IntHolder而报错。所以相比之下,模板构造函数的方案更灵活通用。
内容的提问来源于stack exchange,提问作者c.bear

