c++11 繼承構造函數


若基類擁有數量眾多的不同版本的構造函數,而派生類中只有一些成員函數,則對於派生類而言,其構造函數就等同於構造基類。

struct A {
 A(int i) {}
 A(double d, int i) {}
 A(float f, int i, const char* c) {}
 //...
};

struct B : public: 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 {
public:
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沒有默認構造函數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM