c++11 繼承建構函式
阿新 • • 發佈:2018-12-31
若基類擁有數量眾多的不同版本的建構函式,而派生類中只有一些成員函式,則對於派生類而言,其建構函式就等同於構造基類。
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宣告來宣告繼承基類的建構函式。在剛開始的程式碼可以改造成如下:
structA { 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沒有預設建構函式