继承构造函数

引言

在继承体系中,假设派生类想要使用基类的构造函数,须要在构造函数中显式声明。但此时会伴随一个问题,假若基类拥有众多不同版本的构造函数。则在派生类中需要编写非常多相应的"透传"构造函数。例如:
 1 struct A
 2 {
 3     A(int i) {}
 4     A(double d, int i) {}
 5     A(float f, int i, const char* c) {}
 6     //...等等系列的构造函数版本号
 7 };
 8 struct B :A
 9 {
10     B(int i) :A(i) {}
11     B(double d, int i) :A(d, i) {}
12     B(folat f, int i, const char* c) :A(f, i, e) {}
13     //......等等好多个和基类构造函数相应的构造函数
14 };
非常明显当基类构造函数一多,派生类构造函数的写法就显得非常累赘,相当不方便。

继承构造函数

在继承关系中,有一种现象叫“OverWrite”,即在派生类中的成员函数与基类中的成员函数同名。此时,基类中的成员函数将会隐藏。

  • 函数同名,参数不同
  • 函数同名,参数相同,无virtual关键字修饰

如果在派生类中需要使用基类中的同名成员函数,可以使用using声明实现,例如:

 1 struct A
 2 {
 3     void func(int a) {}
 4 };
 5 
 6 struct B : public A
 7 {
 8     using A::func;        //
 9     void func(const char* pBuf) {}
10 };
11 
12 int main()
13 {
14     B b;
15     b.func(10);        //如果不使用using声明,此行将出错
16 }

 上述思想也可应用在构造函数中:

 1 struct A
 2 {
 3     A(int i) {}
 4     A(double d, int i) {}
 5     A(float f, int i, const char* c) {}
 6     //...各种构造函数版本
 7 };
 8 struct B :A
 9 {
10     using A::A;
11     //一句话搞定所有构造函数
12     //......
13 };

 

如今,通过using A::A的声明。将基类中的构造函数全继承到派生类中,更巧妙的是,假设一个继承构造函数不被相关的代码使用,编译器不会为之产生真正的函数代码,这样比透传基类各种构造函数更加节省目标代码空间。
但此时另一个问题:
当使用using语句继承基类构造函数时,派生类无法对类自身定义的新的类成员进行初始化,即无法在定义派生类构造函数,我们可使用类成员的初始化表达式,为派生类成员设定一个默认初始值。例如:
 1 struct A
 2 {
 3     A(int i) {}
 4     A(double d, int i) {}
 5     A(float f, int i, const char* c) {}
 6 };
 7 
 8 struct B : public A
 9 {
10     using A::A;
11     float m_f = 10.0f;        //使用默认值
12 };
在多继承下,如果多个父类拥有相同参数类型的构造函数,会造成继承构造函数冲突的情况,例如:
1 struct A { A(int i) { } };
2 
3 struct B { B(int i) { } };
4 
5 struct C : public A, public B
6 {
7     using A::A;
8     using B::B;
9 };
此时,可以显式定义继承类的冲突的构造函数,阻止隐式生成相应的继承构造函数来解决冲突。例如:
1 struct C : public A, public B
2 {
3     using A::A;
4     using B::B;
5      C(int) { }         //显示定义
6 };    
有几个点需要注意:
  • 一旦使用了继承构造函数,编译器就不会再为派生类生成默认构造函数。
  • 如果父类的构造函数被声明为私有,或者派生类是从基类中虚继承的,无法声明继承构造函数。
 1 class A
 2 {
 3     A(int a) {}
 4 };
 5 
 6 class B : public A
 7 {
 8 public:
 9     using A::A;
10 };
11 
12 int main()
13 {
14     B b;        //error 无法引用"B"的默认构造函数,它是已删除的函数
15 }

 参考

深入理解C++11:C++11新特性解析与应用

posted @ 2023-11-10 13:56  西兰花战士  阅读(18)  评论(0编辑  收藏  举报