在C++中,類的對象建立分為兩種,一種是靜態建立,如A a;另一種是動態建立,如A* ptr=new A;這兩種方式是有區別的。
靜態建立一個類對象,是由編譯器為對象在棧空間中分配內存,是通過直接移動棧頂指針,挪出適當的空間,然后在這片內存空間上調用構造函數形成一個棧對象。使用這種方法,直接調用類的構造函數。
動態建立類對象,是使用new運算符將對象建立在堆空間中。這個過程分為兩步,第一步是執行operator new()函數,在堆空間中搜索合適的內存並進行分配;第二步是調用構造函數構造對象,初始化這片內存空間。這種方法,間接調用類的構造函數。
那么如何限制類對象只能在堆或者棧上建立呢?下面分別進行討論。
1、只能建立在堆上
當對象建立在棧上面時,是由編譯器分配內存空間的,調用構造函數來構造棧對象。當對象使用完后,編譯器會調用析構函數來釋放棧對象所占的空間。C++是靜態綁定語言,編譯器管理了對象的整個生命周期。如果,類的析構函數是私有的,編譯器無法調用析構函數來釋放內存。所以,編譯器在為類對象分配棧空間時,會先檢查類的析構函數的訪問性,如果類的析構函數是私有的,則編譯器不會在棧空間上為類對象分配內存。
因此,將析構函數設為私有,類對象就無法建立在棧上了。代碼如下:
class A { public : A(){} void destory(){ delete this ;} private : ~A(){} };
- 類中必須提供一個destory函數,來進行內存空間的釋放
- 無法解決繼承問題。如果A作為其它類的基類,則析構函數通常要設為virtual,然后在子類重寫,以實現多態。因此析構函數不能設為private。還好C++提供了第三種訪問控制,protected。將析構函數設為protected可以有效解決這個問題,類外無法訪問protected成員,子類則可以訪問。
2、只能在棧上生成對象:將new 和 delete 重載為私有。
原因:在堆上生成對象,使用new關鍵詞操作,其過程分為兩階段:第一階段,使用new在堆上尋找可用內存,分配給對象;第二階段,調用構造函數生成對象。
將new操作設置為私有,那么第一階段就無法完成,就不能夠再堆上生成對象。
class A { private : void * operator new ( size_t t){} // 注意函數的第一個參數和返回值都是固定的 void operator delete ( void * ptr){} // 重載了new就需要重載delete public : A(){} ~A(){} };
參考鏈接:https://www.nowcoder.com/questionTerminal/0a584aa13f804f3ea72b442a065a7618