这种选择性构造函数“继承”方式是否符合C++标准?
C++选择性继承基类构造函数的标准合规性解析
问题场景
尝试实现仅继承基类部分构造函数时,在GCC上可通过以下方式实现:
#include <string> #include <iostream> struct B { B() { std::cout << std::string("B::B() called") << std::endl; } B(int) { std::cout << std::string("B::B(int) called") << std::endl; } B(long) { std::cout << std::string("B::B(long) called") << std::endl; } B(long, long) { std::cout << std::string("B::B(long, long) called") << std::endl; } }; struct D : public B { D(int) = delete; D(long, long) { std::cout << std::string("D::D(long, long) called") << std::endl; } using B::B; }; #pragma GCC diagnostic push // Ignore warnings from unused variables #pragma GCC diagnostic ignored "-Wunused-variable" int main() { B b0; B b1(1); B b2(1, 2); D d0; // D d1(1); error despite we might wish B::B(long) to be selected D d2(1, 2); } #pragma GCC diagnostic pop
具体做法是:通过using B::B引入基类所有构造函数,再在派生类中通过delete声明或自定义构造函数的方式,覆盖不需要的重载。同时发现using声明和派生类构造函数的声明顺序不影响结果。
核心疑问:
- 这种实现方式是否符合C++标准?
using声明顺序无关的特性是否符合标准?
注:该方式并非完全意义上的选择性继承,因为被delete的重载仍会参与重载解析(如注释行D d1(1)会报错,而非匹配基类的B(long)构造函数)。
解答
1. 该实现方式符合C++标准
根据C++标准,using Base::Base会将基类的所有构造函数引入到派生类的作用域中,与派生类自身声明的构造函数共同组成重载集合。当派生类中存在与基类构造函数签名完全匹配的构造函数(包括delete声明的版本)时,重载解析会优先匹配派生类的版本:
- 对于自定义的
D(long, long),调用D(1,2)时会直接匹配该构造函数,而非基类的版本; - 对于
D(int)=delete,调用D(1)时,int类型实参会精确匹配这个被删除的构造函数,触发编译错误,而不会去匹配需要隐式转换的B(long)。
这种通过派生类声明覆盖基类继承构造函数的行为,是标准允许的。
2. using声明顺序不影响结果也符合标准
在C++类的作用域中,成员的声明顺序不会影响重载解析的最终结果。无论是先声明派生类自己的构造函数,还是先写using B::B,最终派生类作用域内的所有构造函数(包括引入的基类构造函数和自定义/delete的版本)都会被纳入同一个重载集合。重载解析仅依据函数签名的匹配度,而非声明顺序,所以顺序的不同不会改变最终的匹配结果。
内容的提问来源于stack exchange,提问作者skyking
相关产品推荐
相关产品推荐

