国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

《More Effective C++》條款27:如何讓類對象只在棧(堆)上分配空間?

2019-11-08 20:24:51
字體:
供稿:網(wǎng)友

一般情況下,編寫一個(gè)類,是可以在棧或者堆分配空間。但有些時(shí)候,你想編寫一個(gè)只能在棧或者只能在堆上面分配空間的類。這能不能實(shí)現(xiàn)呢?仔細(xì)想想,其實(shí)也是可以滴。

在C++中,類的對象建立分為兩種,一種是靜態(tài)建立,如A a;另一種是動(dòng)態(tài)建立,如A* ptr=new A;這兩種方式是有區(qū)別的。

1、靜態(tài)建立類對象:是由編譯器為對象在棧空間中分配內(nèi)存,是通過直接移動(dòng)棧頂指針,挪出適當(dāng)?shù)目臻g,然后在這片內(nèi)存空間上調(diào)用構(gòu)造函數(shù)形成一個(gè)棧對象。使用這種方法,直接調(diào)用類的構(gòu)造函數(shù)。

2、動(dòng)態(tài)建立類對象,是使用new運(yùn)算符將對象建立在堆空間中。這個(gè)過程分為兩步,第一步是執(zhí)行Operator new()函數(shù),在堆空間中搜索合適的內(nèi)存并進(jìn)行分配;第二步是調(diào)用構(gòu)造函數(shù)構(gòu)造對象,初始化這片內(nèi)存空間。這種方法,間接調(diào)用類的構(gòu)造函數(shù)。

那么如何限制類對象只能在堆或者棧上建立呢?下面分別進(jìn)行討論。

1、只能在堆上分配類對象,就是不能靜態(tài)建立類對象,即不能直接調(diào)用類的構(gòu)造函數(shù)。

容易想到將構(gòu)造函數(shù)設(shè)為私有。在構(gòu)造函數(shù)私有之后,無法在類外部調(diào)用構(gòu)造函數(shù)來構(gòu)造類對象,只能使用new運(yùn)算符來建立對象。然而,前面已經(jīng)說過,new運(yùn)算符的執(zhí)行過程分為兩步,C++提供new運(yùn)算符的重載,其實(shí)是只允許重載operator new()函數(shù),而operatornew()函數(shù)只用于分配內(nèi)存,無法提供構(gòu)造功能。因此,這種方法不可以。

當(dāng)對象建立在棧上面時(shí),是由編譯器分配內(nèi)存空間的,調(diào)用構(gòu)造函數(shù)來構(gòu)造棧對象。當(dāng)對象使用完后,編譯器會(huì)調(diào)用析構(gòu)函數(shù)來釋放棧對象所占的空間。編譯器管理了對象的整個(gè)生命周期。如果編譯器無法調(diào)用類的析構(gòu)函數(shù),情況會(huì)是怎樣的呢?比如,類的析構(gòu)函數(shù)是私有的,編譯器無法調(diào)用析構(gòu)函數(shù)來釋放內(nèi)存。所以,編譯器在為類對象分配棧空間時(shí),會(huì)先檢查類的析構(gòu)函數(shù)的訪問性,其實(shí)不光是析構(gòu)函數(shù),只要是非靜態(tài)的函數(shù),編譯器都會(huì)進(jìn)行檢查。如果類的析構(gòu)函數(shù)是私有的,則編譯器不會(huì)在棧空間上為類對象分配內(nèi)存。因此,將析構(gòu)函數(shù)設(shè)為私有,類對象就無法建立在棧上了。代碼如下:

[cpp] view plain copyclass A  {  public:      A(){}      void destory(){delete this;}  PRivate:      ~A(){}  };  試著使用A a;來建立對象,編譯報(bào)錯(cuò),提示析構(gòu)函數(shù)無法訪問。這樣就只能使用new操作符來建立對象,構(gòu)造函數(shù)是公有的,可以直接調(diào)用。類中必須提供一個(gè)destory函數(shù),來進(jìn)行內(nèi)存空間的釋放。類對象使用完成后,必須調(diào)用destory函數(shù)。

上述方法的缺點(diǎn):

 一、無法解決繼承問題。如果A作為其它類的基類,則析構(gòu)函數(shù)通常要設(shè)為virtual,然后在子類重寫,以實(shí)現(xiàn)多態(tài)。因此析構(gòu)函數(shù)不能設(shè)為private。還好C++提供了第三種訪問控制,protected。將析構(gòu)函數(shù)設(shè)為protected可以有效解決這個(gè)問題,類外無法訪問protected成員,子類則可以訪問。

 二、類的使用很不方便,使用new建立對象,卻使用destory函數(shù)釋放對象,而不是使用delete。(使用delete會(huì)報(bào)錯(cuò),因?yàn)閐elete對象的指針,會(huì)調(diào)用對象的析構(gòu)函數(shù),而析構(gòu)函數(shù)類外不可訪問)這種使用方式比較怪異。為了統(tǒng)一,可以將構(gòu)造函數(shù)設(shè)為protected,然后提供一個(gè)public的static函數(shù)來完成構(gòu)造,這樣不使用new,而是使用一個(gè)函數(shù)來構(gòu)造,使用一個(gè)函數(shù)來析構(gòu)。代碼如下,類似于單例模式

[cpp] view plain copyclass A  {  protected:      A(){}      ~A(){}  public:      static A* create()      {          return new A();      }      void destory()      {          delete this;      }  };  

這樣,調(diào)用create()函數(shù)在堆上創(chuàng)建類A對象,調(diào)用destory()函數(shù)釋放內(nèi)存。

2、只能在棧上分配類對象

只有使用new運(yùn)算符,對象才會(huì)建立在堆上,因此,只要禁用new運(yùn)算符就可以實(shí)現(xiàn)類對象只能建立在棧上。雖然你不能影響new operator的能力(因?yàn)槟鞘荂++語言內(nèi)建的),但是你可以利用一個(gè)事實(shí):new operator 總是先調(diào)用 operator new,而后者我們是可以自行聲明重寫的。因此,將operator new()設(shè)為私有即可禁止對象被new在堆上。代碼如下:

[cpp] view plain copyclass A  {  private:      void* operator new(size_t t){}     // 注意函數(shù)的第一個(gè)參數(shù)和返回值都是固定的      void operator delete(void* ptr){} // 重載了new就需要重載delete  public:      A(){}      ~A(){}  };  參考:

1、http://blog.csdn.net/g5dsk/article/details/4775144

2、http://www.cnblogs.com/h2-database/archive/2012/06/28/2572497.html


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 洛浦县| 南溪县| 白银市| 城固县| 德格县| 阿图什市| 灵台县| 新乡市| 嘉鱼县| 喀喇沁旗| 仙桃市| 上栗县| 沁水县| 固原市| 孟津县| 松桃| 易门县| 东光县| 师宗县| 永靖县| 元朗区| 桃园市| 浦县| 株洲县| 游戏| 灵川县| 新绛县| 东阿县| 金平| 将乐县| 南昌县| 南城县| 梨树县| 唐海县| 班玛县| 玉门市| 汉川市| 延津县| 汝城县| 华池县| 巴林右旗|