若基类拥有数量众多的不同版本的构造函数,而派生类中只有一些成员函数,则对于派生类而言,其构造函数就等同于构造基类。
struct A { A(int i) {} A(double d, int i) {} A(float f, int i, const char* c) {} //... }; struct B : A { B(int i): A(i) {} B(double d, int i): A(d, i) {} B(float f, int i, const char* c): A(f, i c) {} //... virtual void ExtraInterface() {} };
如上,B继承于A,只添加了一个接口,但在构造B时想要拥有A这样的构造方法时,就必须一一透传各个接口。
在C++中,如果派生类想要使用基类的成员函数,可以通过using声明来完成。如下:
#include <iostream> using namespace std; struct Base { void f(double i) { cout << "Base: " << i << endl; } }; struct Derived: Base { using Base::f; void f(int i) { cout << "Derived: " << i << endl;} }; int main() { Base b; b.f(4.5); // Base: 4.5 Derived d; d.f(4.5); // Base: 4.5 d.f(4); // Derived: 4 return 0; }
基类和派生类都声明了函数f,而使用过using声明后,派生类也可以使用基类版本的函数f,这样派生类中就有了两个f函数的版本。
在c++11中,此方法扩展到构造函数上,子类可以通过using声明来声明继承基类的构造函数。在刚开始的代码可以改造成如下:
struct A { A(int i) {} A(double d, int i) {} A(float f, int i, const char* c) {} }; struct B : A { using A::A; virtual void ExtraInterface() {} };
通过 using A::A的声明,将基类中的构造函数悉数集成到派生类B中。且标准继承构造函数和派生类的各种类默认函数(默认构造、析构、拷贝构造等)一样,是隐式声明的。意味着一个继承构造函数不被相关代码使用,则编译器不会为其产生真正的函数代码。
若基类构造函数含有默认值,则对于继承构造函数来说,参数的默认值不会被继承,但会导致基类产生多个构造函数的版本,而这些函数版本都会被派生类继承。
struct A { A(int a = 3, double b = 2.4); }; struct B : A{ using A::A; };
A的构造函数可能有A(int = 3, double = 2.4); A(int = 3); A(const A &); A();则相应地,B中的构造函数也会有:
B(int, double); B(int); B(const B &); B();
若碰到继承构造函数冲突的问题,需要通过显示定义继承类的冲突的构造函数,阻止隐式生成相应的继承构造函数。如下:
struct A { A(int) {} }; struct B { B(int) {} }; struct C: A, B { using A::A; using B::B; //会造成冲突 }; //使用显示定义来解决: struct C: A, B { using A::A; using B::B; C(int) {} //显示定义 };
注意的问题:
如果基类的构造函数被声明为私有成员函数,或者派生类是从基类中虚继承的,那么就不能够在派生类中声明继承构造函数。且一旦使用继承构造函数,编译器就不会再为派生类生成默认构造函数。
struct A { A(int) {}}; struct B : A { using A::A; }; B b; //B没有默认构造函数
原文地址:https://www.cnblogs.com/sssblog/p/10202601.html