1. 程式人生 > >C++11中的繼承建構函式

C++11中的繼承建構函式

時間:2014.06.19

地點:基地

-------------------------------------------------------------------------

一、問題描述

  在繼承體系中,如果派生類想要使用基類的建構函式,需要在建構函式中顯式宣告。如下:

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

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

又在建構函式中呼叫A的建構函式,從而完成建構函式的傳遞。
又比如如下,當B中存在成員變數時:
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){}
  //......等等好多個和基類建構函式對應的建構函式
};

很明顯當基類建構函式一多,派生類建構函式的寫法就顯得很累贅,相當不方便。

-------------------------------------------------------------------------

二、問題的解決

  我們可以通過using宣告來完成這個問題的簡化,看一個例子

<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.如果一旦使用了繼承建構函式,編譯器就不會為派生類生成預設建構函式。這樣,我們得注意繼承建構函式無參版本是不是有需要。




相關推薦

lamnda函式--c++11的匿名函式

C++11提供了對匿名函式的支援,稱為Lambda函式(也叫Lambda表示式). Lambda表示式具體形式如下:     [capture](parameters)->return-type{body} 為什麼說 lambda 表示式如此激動人心呢?舉一個例

C++類一個建構函式呼叫另一個建構函式

class A { int a; int b; int c; public: A(int aa, int bb) : a(aa), b(bb),c(0) { cout << "aa bb" << endl; } A(int aa, in

C++11標準---委託建構函式

委託建構函式 1.概念:一個委託建構函式通過所屬類的其它建構函式執行自己的初始化功能,或者是說把自己的職責委託給了其它建構函式去完成 2.格式 與成員初始化列表初始化成員變數類似,在建構函式後面用:號連線一個建構函式 下面的例項中,兩個委託建構函式把自己的職責交給了其他

C++類拷貝建構函式詳解

a. C++標準中提到“The default constructor, copy constructor and copy assignment operator, and destructor are special member functions.[Note: T

C++11繼承建構函式

時間:2014.06.19 地點:基地 ------------------------------------------------------------------------- 一、問題描述   在繼承體系中,如果派生類想要使用基類的建構函式,需要在建構函式中顯式

c++11 繼承建構函式

若基類擁有數量眾多的不同版本的建構函式,而派生類中只有一些成員函式,則對於派生類而言,其建構函式就等同於構造基類。 struct A { A(int i) {} A(double d, int i) {} A(float f, int i, const char* c) {} //... };

C++繼承建構函式呼叫順序

class B1 {public: B1(int i) {cout<<"consB1"<<i<<endl;} };//定義基類B1 class B2 {public: B2(int j) {cout<<"consB2"<<

C++)C++類繼承建構函式和解構函式

#include <iostream> using namespace std; class Shape{ public: void Draw() {cout<<"Base::Draw()"<<endl;} void Erase() {co

C++11std::move、std::forward、左右值引用、移動建構函式的測試

關於C++11新特性之std::move、std::forward、左右值引用網上資料已經很多了,我主要針對測試效能做一個測試,梳理一下這些邏輯,首先,左值比較熟悉,右值就是臨時變數,意味著使用一次就不會再被使用了。針對這兩種值引入了左值引用和右值引用,以及引用摺疊的概念。 1.右值引用的舉例測試 #in

java繼承--子父類建構函式

1 子父類建構函式的特點 在子類構造物件時,發現,訪問子類建構函式時,父類建構函式也運行了。 原因是:在子類的建構函式中第一行有一個預設的隱式語句。 super(); 類似於this(); this();呼叫的是本類的建構函式 子類建構函式預設呼叫的是父類中的空引數建構函式

c++ 11 顯式預設設定的函式和已刪除的函式 總結

今天在一個類中看到如下程式碼不是很懂,原來是c++11 新特性 RateTimer(const RateTimer&) = delete; //不可拷貝/不可賦值 RateTimer& operator=(const RateTimer&) = delete;

C++預設建構函式建構函式初始化列表

1、預設建構函式和建構函式 (1)建構函式:C++用於構建類的新物件時需要呼叫的函式,該函式無返回型別!(注意:是“無”! 不是空!(void))。 (2)預設建構函式:預設建構函式是在呼叫時不需要顯示地傳入實參的建構函式。 一個類如果自己沒有定義建構函式,則會有一個無參且函式體也是空的

C++建構函式和解構函式

1:建構函式 處理物件的初始化。特殊的成員函式,不需要使用者來呼叫,而是在建立物件的時候自動執行。 特點: ①與類名相同 ②沒有任何返回型別 ③定義時可以有引數,可以無引數 2:解構函式 語法 :~cl

C++為什麼建構函式不能定義為虛擬函式

關於C++為什麼不支援虛擬建構函式,Bjarne很早以前就在C++Style and Technique FAQ裡面做過回答 Avirtual call is a mechanism to get work done given partialinformation. In particular

c++11多執行緒Join函式

寫在前面 Join函式作用: Join thread The function returns when the thread execution has completed.//直到執行緒完成函式才返回 This synchronizes the moment t

淺談c++建構函式

下面所有的建構函式都將用Student這個類作為例子 class Student { private: static int count;//不屬於任何一個物件 std::string name; char *gender; i

C++,編譯器會預設提供的建構函式有哪幾種? C++預設建構函式有幾種,詳細描述每一種。

答:         只有一種,預設建構函式。(不帶引數的建構函式) 答: 兩種:         1.不帶有任何引數的建構函式。比如 Example();如果使用者沒有定義任何建構函式,則編譯器會

C++建構函式與建立物件的(簡單)過程

<pre name="code" class="cpp">//構造方法 #pragma 在做遊戲的公司裡面初始化的方法有兩種風格 一種是init這是本來做蘋果轉過來的 另外一種是在構造方法裡面初始化 (這本來就是做C++的) #include <iostream> using

C++拷貝建構函式、淺拷貝與深拷貝的詳解

拷貝建構函式呼叫時機: 1、物件需要通過另外一個物件進行初始 化:     T t1(10, 20);T t2(0, 0);T t3 = t1; // 拷貝建構函式呼叫的時機一:T t4(t2);  // 拷貝建構函式呼叫的時機 二:2、實參傳遞給形參時呼叫賦值建構函式 拷

C++ 拷貝建構函式被呼叫情況

1、當用類的一個物件初始化該類的另一個物件時.例如: Int main(){       Point A;       Point B(A);// } 2 如果函式的形參是類的物件,呼叫函式時,進行形參和實參結合時. void fun(Point P){ } int