C/Cpp / 如何定义一个只能在堆上(栈上)生成对象的类?
在 C++ 中,類的對象建立分為兩種,一種是靜態(tài)建立,如 A a;另一種是動態(tài)建立,如 A* ptr = new A;這兩種方式是有區(qū)別的。
靜態(tài)建立一個類對象,是由編譯器為對象在棧空間中分配內存,是通過直接移動棧頂指針,挪出適當?shù)目臻g,然后在這片內存空間上調用構造函數(shù)形成一個棧對象。使用這種方法,直接調用類的構造函數(shù)。
動態(tài)建立類對象,是使用 new 運算符將對象建立在堆空間中。這個過程分為兩步,第一步是執(zhí)行 operator new() 函數(shù),在堆空間中搜索合適的內存并進行分配;第二步是調用構造函數(shù)構造對象,初始化這片內存空間。這種方法,間接調用類的構造函數(shù)。
? ? ? ? 那么如何限制類對象只能在堆或者棧上建立呢?下面分別進行討論。
1、只能建立在堆上
類對象只能建立在堆上,就是不能靜態(tài)建立類對象,即不能直接調用類的構造函數(shù)。
容易想到將構造函數(shù)設為私有。在構造函數(shù)私有之后,無法在類外部調用構造函數(shù)來構造類對象,只能使用 new 運算符來建立對象。然而,前面已經(jīng)說過,new 運算符的執(zhí)行過程分為兩步,C++提供 new運算符的重載,其實是只允許重載 operator new() 函數(shù),而 operator() 函數(shù)用于分配內存,無法提供構造功能。因此,這種方法不可以。
當對象建立在棧上面時,是由編譯器分配內存空間的,調用構造函數(shù)來構造棧對象。當對象使用完后,編譯器會調用析構函數(shù)來釋放棧對象所占的空間。編譯器管理了對象的整個生命周期。如果編譯器無法調用類的析構函數(shù),情況會是怎樣的呢?比如,類的析構函數(shù)是私有的,編譯器無法調用析構函數(shù)來釋放內存。所以,編譯器在為類對象分配棧空間時,會先檢查類的析構函數(shù)的訪問性,其實不光是析構函數(shù),只要是非靜態(tài)的函數(shù),編譯器都會進行檢查。如果類的析構函數(shù)是私有的,則編譯器不會在棧空間上為類對象分配內存。
? ? ? ? 因此,將析構函數(shù)設為私有,類對象就無法建立在棧上了。代碼如下:
class A { public : A(){} void destory(){ delete this ;} private : ~A(){} };試著使用 A a; 來建立對象,編譯報錯,提示析構函數(shù)無法訪問。這樣就只能使用 new 操作符來建立對象,構造函數(shù)是公有的,可以直接調用。類中必須提供一個 destory 函數(shù),來進行內存空間的釋放。類對象使用完成后,必須調用 destory 函數(shù)。
上述方法的一個缺點就是,無法解決繼承問題。如果 A 作為其它類的基類,則析構函數(shù)通常要設為 virtual,然后在子類重寫,以實現(xiàn)多態(tài)。因此析構函數(shù)不能設為 private。還好 C++ 提供了第三種訪問控制,protected。將析構函數(shù)設為 protected 可以有效解決這個問題,類外無法訪問protected成員,子類則可以訪問。
另一個問題是,類的使用很不方便,使用 new 建立對象,卻使用 destory 函數(shù)釋放對象,而不是使用 delete。(使用delete會報錯,因為 delete 對象的指針,會調用對象的析構函數(shù),而析構函數(shù)類外不可訪問)這種使用方式比較怪異。為了統(tǒng)一,可以將構造函數(shù)設為 protected,然后提供一個 public 的 static 函數(shù)來完成構造,這樣不使用 new,而是使用一個函數(shù)來構造,使用一個函數(shù)來析構。代碼如下,類似于單例模式:
class A { protected : A(){} ~A(){} public : static A* create() { return new A(); } void destory() { delete this ; } };? ? ? ? 這樣,調用 create() 函數(shù)在堆上創(chuàng)建類 A 對象,調用 destory() 函數(shù)釋放內存。
2、只能建立在棧上
只有使用 new 運算符,對象才會建立在堆上,因此,只要禁用 new 運算符就可以實現(xiàn)類對象只能建立在棧上。將 operator new() 設為私有即可。代碼如下:
class A { private : void * operator new ( size_t t){} // 注意函數(shù)的第一個參數(shù)和返回值都是固定的。 void operator delete ( void * ptr){} // 重載了 new 就需要重載 delete 。public : A(){} ~A(){} };?
鏈接:https://www.nowcoder.com/questionTerminal/0a584aa13f804f3ea72b442a065a7618
來源:牛客網(wǎng)?
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的C/Cpp / 如何定义一个只能在堆上(栈上)生成对象的类?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/Cpp / Cpp 中 struct
- 下一篇: Cpp / 右值、纯右值、将亡值