C++中虛繼承時的構(gòu)造函數(shù)示例詳解
在虛繼承中,虛基類是由最終的派生類初始化的,換句話說,最終派生類的構(gòu)造函數(shù)必須要調(diào)用虛基類的構(gòu)造函數(shù)。對最終的派生類來說,虛基類是間接基類,而不是直接基類。這跟普通繼承不同,在普通繼承中,派生類構(gòu)造函數(shù)中只能調(diào)用直接基類的構(gòu)造函數(shù),不能調(diào)用間接基類的。
下面我們以菱形繼承為例來演示構(gòu)造函數(shù)的調(diào)用:
#include <iostream> using namespace std; //虛基類A class A{ public: A(int a); protected: int m_a; }; A::A(int a): m_a(a){ } //直接派生類B class B: virtual public A{ public: B(int a, int b); public: void display(); protected: int m_b; }; B::B(int a, int b): A(a), m_b(b){ } void B::display(){ cout<<"m_a="<<m_a<<", m_b="<<m_b<<endl; } //直接派生類C class C: virtual public A{ public: C(int a, int c); public: void display(); protected: int m_c; }; C::C(int a, int c): A(a), m_c(c){ } void C::display(){ cout<<"m_a="<<m_a<<", m_c="<<m_c<<endl; } //間接派生類D class D: public B, public C{ public: D(int a, int b, int c, int d); public: void display(); private: int m_d; }; D::D(int a, int b, int c, int d): A(a), B(90, b), C(100, c), m_d(d){ } void D::display(){ cout<<"m_a="<<m_a<<", m_b="<<m_b<<", m_c="<<m_c<<", m_d="<<m_d<<endl; } int main(){ B b(10, 20); b.display(); C c(30, 40); c.display(); D d(50, 60, 70, 80); d.display(); return 0; }
運(yùn)行結(jié)果:
m_a=10, m_b=20
m_a=30, m_c=40
m_a=50, m_b=60, m_c=70, m_d=80
請注意第 50 行代碼,在最終派生類 D 的構(gòu)造函數(shù)中,除了調(diào)用 B 和 C 的構(gòu)造函數(shù),還調(diào)用了 A 的構(gòu)造函數(shù),這說明 D 不但要負(fù)責(zé)初始化直接基類 B 和 C,還要負(fù)責(zé)初始化間接基類 A。
而在以往的普通繼承中,派生類的構(gòu)造函數(shù)只負(fù)責(zé)初始化它的直接基類,再由直接基類的構(gòu)造函數(shù)初始化間接基類,用戶嘗試調(diào)用間接基類的構(gòu)造函數(shù)將導(dǎo)致錯誤?,F(xiàn)在采用了虛繼承,虛基類 A 在最終派生類 D 中只保留了一份成員變量 m_a,如果由 B 和 C 初始化 m_a,那么 B 和 C 在調(diào)用 A 的構(gòu)造函數(shù)時很有可能給出不同的實(shí)參,這個時候編譯器就會犯迷糊,不知道使用哪個實(shí)參初始化 m_a。
為了避免出現(xiàn)這種矛盾的情況,C++ 干脆規(guī)定必須由最終的派生類 D 來初始化虛基類 A,直接派生類 B 和 C 對 A 的構(gòu)造函數(shù)的調(diào)用是無效的。在第 50 行代碼中,調(diào)用 B 的構(gòu)造函數(shù)時試圖將 m_a 初始化為 90,調(diào)用 C 的構(gòu)造函數(shù)時試圖將 m_a 初始化為 100,但是輸出結(jié)果有力地證明了這些都是無效的,m_a 最終被初始化為 50,這正是在 D 中直接調(diào)用 A 的構(gòu)造函數(shù)的結(jié)果。另外需要關(guān)注的是構(gòu)造函數(shù)的執(zhí)行順序。
虛繼承時構(gòu)造函數(shù)的執(zhí)行順序與普通繼承時不同:在最終派生類的構(gòu)造函數(shù)調(diào)用列表中,不管各個構(gòu)造函數(shù)出現(xiàn)的順序如何,編譯器總是先調(diào)用虛基類的構(gòu)造函數(shù),再按照出現(xiàn)的順序調(diào)用其他的構(gòu)造函數(shù);而對于普通繼承,就是按照構(gòu)造函數(shù)出現(xiàn)的順序依次調(diào)用的。修改本例中第 50 行代碼,改變構(gòu)造函數(shù)出現(xiàn)的順序:
D::D(int a, int b, int c, int d): B(90, b), C(100, c), A(a), m_d(d){ }
雖然我們將 A() 放在了最后,但是編譯器仍然會先調(diào)用 A(),然后再調(diào)用 B()、C(),因?yàn)?A() 是虛基類的構(gòu)造函數(shù),比其他構(gòu)造函數(shù)優(yōu)先級高。如果沒有使用虛繼承的話,那么編譯器將按照出現(xiàn)的順序依次調(diào)用 B()、C()、A()。
到此這篇關(guān)于C++中虛繼承時的構(gòu)造函數(shù)示例詳解的文章就介紹到這了,更多相關(guān)C++虛繼承構(gòu)造函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言 pthread_create() 函數(shù)講解
這篇文章主要介紹了C語言 pthread_create() 函數(shù)講解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C語言使用函數(shù)實(shí)現(xiàn)字符串部分復(fù)制問題
這篇文章主要介紹了C語言使用函數(shù)實(shí)現(xiàn)字符串部分復(fù)制問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11C++ Array容器的顯示和隱式實(shí)例化詳細(xì)介紹
這篇文章主要介紹了C++中Array容器的隱式實(shí)例化和顯式實(shí)例化,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10

C++實(shí)現(xiàn)假裝藍(lán)屏整蠱小程序

C/C++實(shí)現(xiàn)7bit與8bit編碼互相轉(zhuǎn)換

深入理解C++?字符變量取地址的特殊性與內(nèi)存管理機(jī)制詳解

OpenCV實(shí)現(xiàn)低對比度圖像臟污區(qū)域檢測