C++11中的繼承構造函數

時間:2014.06.19函數

地點:基地spa

-------------------------------------------------------------------------code

1、問題描寫敘述

  在繼承體系中,假設派生類想要使用基類的構造函數,需要在構造函數中顯式聲明。blog

例如如下:繼承

struct A
{
   A(int i){}
};

struct B:A
{
  B(int i):A(i){}
};
在這裏,B派生於A,B

又在構造函數中調用A的構造函數。從而完畢構造函數的傳遞。


又比方例如如下。當B中存在成員變量時: ip

struct A
{
   A(int i){}
};

struct B:A
{
  B(int i):A(i),d(i){}
  int d;
};
現在派生於A的結構體B包括一個成員變量,咱們在初始化基類A的同一時候也初始化成員d。現在的問題是:倘若基類用於擁有爲數衆多的不一樣版本號的構造函數。這樣,在派生類中按上面的思惟還得寫很是多相應的「透傳」構造函數。例如如下:

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(folat f,int i,const char* c):A(f,i,e){}
  //......等等好多個和基類構造函數相應的構造函數
};

很是明顯當基類構造函數一多,派生類構造函數的寫法就顯得很是累贅,至關不方便。編譯器

-------------------------------------------------------------------------
編譯

2、問題的解決

  咱們可以經過using聲明來完畢這個問題的簡化,看一個樣例class

<pre name="code" class="cpp"><pre name="code" class="cpp">struct Base
{
  void f(double i){
  cout<<"Base:"<<i<<endl;
  }
};

struct Drived:Base
{
  using Base::f;
  void f(int i){
    cout<<"Drived:"<<i<<endl;
  }
};

 
 

代碼中基類和派生類都聲明瞭同名的函數f。但派生類中辦法和基類的版本號不一樣,這裏使用using聲明,說明派生類中也使用基類版本號的函數f。這樣派生類中就擁有兩個f函數的版本號了。在這裏需要說明的是,假設沒有使用using聲明繼承父類同名函數,那麼派生類中定義的f函數將會屏蔽父類的f函數,固然若派生類根本就未定義這個f同名函數。還會選擇用基類的f函數。
這樣的方法,咱們同樣可遷移到構造函數的繼承上。即派生類可以經過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;
  //關於基類各構造函數的繼承一句話搞定
  //......
};
現在,經過using A::A的聲明。將基類中的構造函數全繼承到派生類中,更巧妙的是,這是隱式聲明繼承的。即假設一個繼承構造函數不被相關的代碼使用,編譯器不會爲之產生真正的函數代碼,這樣比透傳基類各類構造函數更加節省目標代碼空間。

但此時另外一個問題:

當使用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;
  int d{0};
};

注意:

  1.對於繼承構造函數來講,參數的默認值是不會被繼承的,而且,默認值會 致使基類產生多個構造函數版本號(即參數從後一直往前面減。直到包括無參構造函數,固然假設是默認複製構造函數也包括在內),這些函數版本號都會被派生類繼承。

  2.繼承構造函數中的衝突處理:當派生類擁有多個基類時,多個基類中的部分構造函數可能致使派生類中的繼承構造函數的函數名。

參數都一樣,那麼繼承類中的繼承構造函數將致使不合法的派生類代碼,比方:

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){}
};
3.假設基類的構造函數被聲明爲私有構造函數或者派生類是從基類虛繼承的,那麼就不能在派生類中聲明繼承構造函數。

4.假設一旦使用了繼承構造函數,編譯器就不會爲派生類生成默認構造函數。這樣,咱們得注意繼承構造函數無參版本號是否是有需要。

相關文章
相關標籤/搜索