C 的黑科技(深入探索C 物件模型)

2021-09-23 18:08:51 字數 2929 閱讀 9077

「如何產生乙個不能被繼承的類」,這道題我反反覆覆只想到,將父類的建構函式私有,讓子類不能呼叫,最後歸結出乙個單例模式,但面試官說,單例模式作為此題的解答不夠靈活,後來面試官提示說,可以用友元+虛繼承,可以完美實現這樣乙個類

當然那時我還不太明白,友元與虛繼承我都極少接觸過,只是知道有這些東西,回頭搜了一下「不能被繼承的類」的做法,具體如下:

1,宣告乙個類,cnoheritance,建構函式為private,並宣告友元類cparent;

2,讓cparent虛繼承cnoheritance

這樣cparent就成為乙個可以被正常例項化,但又不能被繼承的類

吳總當**價說,「呵呵,虛繼承,感覺完全是黑科技啊」

這個黑科技真是戳中我笑點,但想到c++經常有些奇妙的東西,現在想總結一下

自動合成的建構函式往往都是public,在派生類中,它的建構函式是可以被使用的,即派生類不會因此受到限制。

那麼,如何能使派生類不能使用基類的函式或成員呢?

如果乙個類的建構函式宣告為private,則其派生類甚至該類的物件都不能訪問,意味著兩點:

那麼怎麼使用該類呢?一般而言,會通過該類的函式來建立

class a

public:

a& createa()

};

然而,這樣又引申乙個問題:類沒有例項化,如何能使用其成員函式呢?

答案是將該成員函式宣告為static,這樣不需要例項化即可訪問,即將上述改為:

class a

public:

static a& createa()

};a object=a::createa();

很明顯,上面的例項化過程很不方便,簡直是艱辛呀,單例模式的其中一種實現就是如此,在此先不講。這樣實現的類,不能被繼承,但自己也不好過

so,如果用友元來實現,是怎麼實現的呢?

宣告乙個類,及其友元

class a

friend class b;

};

那麼b是可以呼叫a的private的建構函式的,那麼讓b虛繼承a會發生什麼事呢?

由《深度探索c++物件模型》看到,b記憶體中將有乙份a類的實體,呼叫a的建構函式構造的,這對於友元類b是可行的

class a

friend class b;

};class b : virtual a

;

那麼這樣的b能不能被繼承呢?假設有個類繼承了b,如下

class a

friend class b;

};class b : virtual a

;class c : b

;

考慮到虛繼承的特性,c也將呼叫a的建構函式構造出乙個a,但!!c並不是a的友元類,所以根本不能執行a私有的建構函式,這段程式,如果不例項化c,編譯器不會報錯,但一旦例項化c,則將報錯。

而b是可以正常例項化的乙個類,這樣就完美實現了乙個不能被繼承的類:b

相比於建構函式的各種trick,c++的初始化列表就顯得很容易了,只有那麼一點要注意:

c++的初始化列表的賦值順序,是與c++類裡面成員變數的宣告順序相關,與初始化列表裡的順序無關

舉個例子,以下就會出現莫名錯誤:

class a

public:

int x;

int y;

};

根據宣告順序,在初始化列表中,是先完成x(y)這個步驟,但此時y並沒有被賦值,所以得到的x是個隨機的值。

c++虛函式的問題,幾乎是面試必問,實際上需要了解的東西也挺多,我自己在前幾次面試,都有些理解有誤的地方,或者理解不夠完善

這裡總結幾點吧(以下類都是針對有虛函式的類):

c++的拷貝建構函式是c++預設的四個函式之一:建構函式、析構函式、賦值函式、拷貝建構函式

拷貝建構函式是一種特別的建構函式,在《深度探索c++物件模型》書中說,有三種情況,會導致拷貝建構函式被觸發:

一般情況下,如果沒有提供explicit copy constructor時,會發生什麼呢?

乙個良好的編譯器可以為大部分class objects產生bitwise copies,因為它們有bitwise semantics...

這裡說的很神奇,好像我們不需要自己寫copy constructor也沒問題一樣,實際上,bitwise copies在有些情況下是非常不推崇的

首先解釋下什麼是bitwise copies:這是指,在拷貝過來的時候,把class的記憶體直接位拷貝過來,即可以看成是記憶體拷貝(對應的有值拷貝)

class a

;int main()

這裡可以發現,a1.p的位址與a2.p的位址是一樣的,那麼,我分配的記憶體,該由哪個釋放呢?我釋放了,另乙個怎麼辦呢?

實際上,這種拷貝方式在stl的string裡面肯定是要重寫的,不能用位拷貝。

《深度探索c++物件模型》中,說class不展現出「bitwise copy semantics」有四種情況:

其實主要都是擔心,指標在bitwise semantics下,隨便複製可能會導致不可預料的錯誤

在這裡說一下賦值函式與拷貝建構函式在觸發上的區別:

當乙個object從無到有時,觸發的一定是拷貝建構函式,賦值函式只會在已有的object賦值時,才會觸發

針對虛繼承,可以坦承的一點就是

所有簡單的東西,遇到虛繼承,似乎都要單獨拿出來討論

C 的黑科技(深入探索C 物件模型)

如何產生乙個不能被繼承的類 這道題我反反覆覆只想到,將父類的建構函式私有,讓子類不能呼叫,最後歸結出乙個單例模式,但面試官說,單例模式作為此題的解答不夠靈活,後來面試官提示說,可以用友元 虛繼承,可以完美實現這樣乙個類 當然那時我還不太明白,友元與虛繼承我都極少接觸過,只是知道有這些東西,回頭搜了一...

深入探索C 物件模型

深入探索c 物件模型 本書目錄結構如下 第1章 關於物件 object lessons 加上封裝後的布局成本 layout costs for adding encapsulation 1.1 c 模式模式 the c object model 簡單物件模型 a object model 驅動物件模...

深入探索C 物件模型(6)

物件陣列的構造 物件資料的構造一般有兩種方式 靜態和動態 1 靜態分配 以string類為例,string a 10 就是以靜態形式構造資料,這樣的陣列的個數是確定的不能修改的。像這樣的陣列怎麼進行構造和析構呢?編譯器在構造陣列的時候會生成乙個使用預設建構函式的陣列建構函式arr new char ...