關於C 繼承體系中類的構造與析構的順序 轉貼

2021-04-12 20:41:46 字數 2084 閱讀 2215

class m1                        class m2

m2() 

virtual void mf() {}                virtual void mf() {}

} ;                               };

class c : public b1, public b2

m1 m1;

m2 m2;};

(1)編譯器會不會為c生成預設構造(default ctor)

編譯器只在需要時才會為乙個類生成def ctor。「需要時」指:

a.乙個類有虛函式

b.乙個類有虛基類

c.乙個類的基類有def ctor

d.乙個類的成員類有def ctor

在這裡,class c符合c,d兩個條件,編譯器會為它生成def ctor.

(2)預設構造的內容

編譯器生成的def ctor是這樣的

c::c()

a.按宣告順序構造基類

b.設定虛表指標

c.按宣告順序構造成員類

(3)對自定義建構函式的改造

對於b1,b2,m1,m2,已有建構函式,但編譯器會對其改造,加入一些**,完成必要的初始化工作。改造後的ctor如下:(以b1為例)

b1::b1()

a.設定虛表指標

b.如果使用者寫有**(如i=0),則執行這些**

(4)綜合(2),(3),建構函式完整**如下

t::t()

在使用者**執行前,基類與成員類已構造完畢,虛指標已設定。

所以c的構造順序是:b1-〉b2-〉虛指標設定-〉m1-〉m2->c自己的**(如果有的話)

由(3)可知,每個類的ctor中,都會暫時將虛指標指向自己的虛表。呼叫b1::b1時,虛指標指向b1的虛表,然後在c::c中,虛指標被重新設定為c的虛表。

在繼承體系中,構造是由上而下的,b1或b2構造時,c還未構造。c構造時,b1和b2已構造完成。

所以在繼承體系中,乙個類的建構函式執行時,該類的所有基類已構造完畢,虛指標已設定,所有成員類也已構造完畢。但該類的所有子類均未構造完成。

2.析構函式

(1)編譯器會不會為c生成析構函式(dtor)

編譯器只在需要時才會為乙個類生成dtor。「需要時」指:

a.類的基類有析構

b.類的成員類有析構

與構造不同,少了兩點,因為在乙個類析構時,這是乙個破壞操作(destory),既然類以已經沒用了,何必再把虛指標設一下呢。

(2)析構的內容

編譯器生成的析構是這樣的

c::~c()

a.按宣告順序相反的順序析構成員類

b.按宣告順序相反的順序析構基類

這裡的相反順序是c++標準規定的要求,不同編譯器都應做到,否則不符合標準(實際上編譯器或多或少都有不符標準的地方,當然不是指這裡所說的順序問題)

(3)完整的析構的呼叫順序

對於已有析構函式的類,編譯器會對其改造,加入一些**,完成必要的工作。改造後的dtor如下:

t::~t()

這是完整的析構的呼叫順序

在使用者**執行前,虛指標已重新設定,以便使用者**能正確執行。然後再析構成員類和基類。

所以,如果上面例子中的五個類都有析構函式的話,呼叫順序是:

虛指標設定-〉c自己的**->m2-〉m1-〉b2-〉b1

每個類的dtor中,都會暫時將虛指標指向自己的虛表。呼叫c::~c時,虛指標指向c的虛表,然後在b1::~b1中,虛指標被重新設定為b1的虛表。

可見,在繼承體系中,析構是由下而上的,b1或b2析構時,c已被析構。c析構時,b1和b2還未被析構。

所以在繼承體系中,乙個類的析構函式執行時,該類的所有基類還未被析構,所有成員類也未被析構。但該類的所有子類均已析構完成。

3.虛函式

在構造或析構中呼叫虛函式,會怎樣.如:

b1::b1()

呼叫的是b1::f()還是c::f()

答案是b1::f()

每個類的ctor中,都會暫時將虛指標指向自己的虛表。呼叫b1::b1時,虛指標指向b1的虛表

所以是b1::f()

如果在c的建構函式中呼叫f(),那就呼叫c::f()

c 繼承中的構造與析構

問題 如何初始化父類成員?父類與子類的建構函式的關係?在子類物件構造時,需要呼叫父類建構函式對其繼承得來的成員進行初始化。在子類物件析構時,需要呼叫父類析構函式對其繼承得來的成員進行清理。繼承中的構造與析構呼叫規則 1.子類物件在建立時會首先呼叫父類的建構函式 2.父類建構函式執行結束後,執行子類的...

C 繼承與構造析構

include 子類物件可以當作父類物件使用 子類物件可以直接賦值給父類物件 子類物件可以直接初始化父類物件 父類指標可以直接指向子類物件 父類引用可以直接引用子類物件 子類物件構造時,需要呼叫父類建構函式對其繼承得來的成員進行初始化 子類物件析構時,需要呼叫父類析構函式對其繼承得來的成員進行清理 ...

繼承中的構造與析構

賦值相容性原則 子類物件可以當作父類物件使用 子類物件可以直接賦值給父類物件 子類物件可以直接初始化父類物件 父類指標可以直接指向子類物件 父類引用可以直接引用子類物件 子類是就是特殊的父類!class child public parent int main int argc,char argv ...