最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c++如何控制對象的創(chuàng)建方式(禁止創(chuàng)建棧對象or堆對象)和創(chuàng)建的數(shù)量

 更新時(shí)間:2020年08月13日 16:02:30   作者:Dabelv  
這篇文章主要介紹了c++如何控制對象的創(chuàng)建方式和創(chuàng)建的數(shù)量,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

我們知道,C++將內(nèi)存劃分為三個(gè)邏輯區(qū)域:堆、棧和靜態(tài)存儲(chǔ)區(qū)。既然如此,我稱位于它們之中的對象分別為堆對象,棧對象以及靜態(tài)對象。通常情況下,對象創(chuàng)建在堆上還是在棧上,創(chuàng)建多少個(gè),這都是沒有限制的。但是有時(shí)會(huì)遇到一些特殊需求。

1.禁止創(chuàng)建棧對象

禁止創(chuàng)建棧對象,意味著只能在堆上創(chuàng)建對象。創(chuàng)建棧對象時(shí)會(huì)移動(dòng)棧頂指針以“挪出”適當(dāng)大小的空間,然后在這個(gè)空間上直接調(diào)用類的構(gòu)造函數(shù)以形成一個(gè)棧對象。而當(dāng)棧對象生命周期結(jié)束,如棧對象所在函數(shù)返回時(shí),會(huì)調(diào)用其析構(gòu)函數(shù)釋放這個(gè)對象,然后再調(diào)整棧頂指針收回那塊棧內(nèi)存。在這個(gè)過程中是不需要operator new/delete操作的,所以將operator new/delete設(shè)置為private不能達(dá)到目的。

可以將構(gòu)造函數(shù)或析構(gòu)函數(shù)設(shè)為私有的,這樣系統(tǒng)就不能調(diào)用構(gòu)造/析構(gòu)函數(shù)了,當(dāng)然就不能在棧中生成對象了。這樣的確可以,但有一點(diǎn)需要注意,那就是如果我們將構(gòu)造函數(shù)設(shè)置為私有,那么我們也就不能用new來直接產(chǎn)生堆對象了,因?yàn)閚ew在為對象分配空間后也會(huì)調(diào)用它的構(gòu)造函數(shù)。所以,如果將構(gòu)造函數(shù)和析構(gòu)函數(shù)都聲明為private會(huì)帶來較大的副作用,最好的方法是將析構(gòu)函數(shù)聲明為private,而構(gòu)造函數(shù)保持為public。

再進(jìn)一步,將析構(gòu)函數(shù)設(shè)為private除了會(huì)限制棧對象生成外,還有其它影響嗎?是的,這還會(huì)限制繼承。如果一個(gè)類不打算作為基類,通常采用的方案就是將其析構(gòu)函數(shù)聲明為private。為了限制棧對象,卻不限制繼承,我們可以將析構(gòu)函數(shù)聲明為protected,這樣就兩全其美了。如下代碼所示:

class NoStackObject{ 
protected: 
 ~NoStackObject(){} 
public: 
 void destroy(){ 
  delete this ;//調(diào)用保護(hù)析構(gòu)函數(shù) 
 } 
};

上面的類在創(chuàng)建棧對象時(shí),如NoStackObject obj;時(shí)編譯將會(huì)報(bào)錯(cuò),而采用new的方式,編譯就會(huì)通過。需要注意一點(diǎn)的是,通過new創(chuàng)建堆對象時(shí),在手動(dòng)釋放對象內(nèi)存時(shí),我們需要調(diào)用其析構(gòu)函數(shù),這時(shí)就需要一點(diǎn)技巧來輔助——引入偽析構(gòu)函數(shù)destory,如上面的代碼所示。

方法拓展。 

仔細(xì)一看,我們會(huì)發(fā)現(xiàn)上面的方法讓人別扭。我們用new創(chuàng)建一個(gè)對象,卻不是用delete去刪除它,而是要用destroy方法。很顯然,用戶會(huì)不習(xí)慣這種怪異的使用方式。所以,可以將構(gòu)造函數(shù)也設(shè)為private或protected。這又回到了上面曾試圖避免的問題,即不用new,那么該用什么方式來生成一個(gè)對象了?我們可以用間接的辦法完成,即讓這個(gè)類提供一個(gè)static成員函數(shù)專門用于產(chǎn)生該類型的堆對象。(設(shè)計(jì)模式中的singleton模式就可以用這種方式實(shí)現(xiàn)。)讓我們來看看:

class NoStackObject { 
protected: 
 NoStackObject() { } 
 ~NoStackObject() { } 
public: 
 static NoStackObject* creatInstance() {
 return new NoStackObject() ;//調(diào)用保護(hù)的構(gòu)造函數(shù) 
} 
 void destroy() {
  delete this ;//調(diào)用保護(hù)的析構(gòu)函數(shù) 
 } 
};

現(xiàn)在可以這樣使用NoStackObject類了:

NoStackObject* hash_ptr = NoStackObject::creatInstance() ; 
... ... //對hash_ptr指向的對象進(jìn)行操作 
hash_ptr->destroy() ; 
hash_ptr = NULL ; //防止使用懸掛指針

現(xiàn)在感覺是不是好多了,生成對象和釋放對象的操作一致了。

2.禁止創(chuàng)建堆對象

我們已經(jīng)知道,產(chǎn)生堆對象的唯一方法是使用new操作,如果我們禁止使用new不就行了么。再進(jìn)一步,new操作執(zhí)行時(shí)會(huì)調(diào)用operator new,而operator new是可以重載的。方法有了,就是使new operator 為private,為了對稱,最好將operator delete也重載為private。

class NoStackObject{
private:
 static void* operator new(size_t size);
 static void operator delete(void* ptr);
};

//用戶代碼
NoStackObject obj0;    //OK
static NoStackObject obj1;  //OK
NoStackObject * pObj2 = new NoStackObject; //ERROR

如果也想禁止堆對象數(shù)組,可以把operator new[]和operator delete[]也聲明為private。

這里同樣在繼承時(shí)存在問題,如果派生類改寫了operator new和operator delete并聲明為public,則基類中原有的private版本將失效,參考如下代碼:

class NoStackObject{
protected:
 static void* operator new(size_t size);
 static void operator delete(void* ptr);
};


class NoStackObjectSon:public NoStackObject{
public:
 static void* operator new(size_t size){ //非嚴(yán)格實(shí)現(xiàn),僅作示意之用 
  return malloc(size);
 };
 static void operator delete(void* ptr){ //非嚴(yán)格實(shí)現(xiàn),僅作示意之用 
  free(ptr);
 };
};

//用戶代碼
NoStackObjectSon* pObj2 = new NoStackObjectSon; //OK

3.控制實(shí)例化對象的個(gè)數(shù)

在游戲設(shè)計(jì)中,我們采用類CGameWorld作為游戲場景的抽象描述。然而在游戲運(yùn)行過程中,游戲場景只有一個(gè),也就是對CGameWorld對象的只有一個(gè)。對于對象的實(shí)例化,有一點(diǎn)是十分確定的:要調(diào)用構(gòu)造函數(shù)。所以,如果想控制CGameWorld的實(shí)例化對象只有一個(gè),最簡單的方法就是將構(gòu)造函數(shù)聲明為private,同時(shí)提供一個(gè)static對象。如下:

class CGameWorld
{
public:
 bool Init();
 void Run();
private:
 CGameWorld();
 CGameWorld(const CGameWorld& rhs);

 friend CGameWorld& GetSingleGameWorld();
};

CGameWorld& GetSingleGameWorld()
{
 static CGameWorld s_game_world;
 return s_game_world;
}

這個(gè)設(shè)計(jì)有三個(gè)要點(diǎn): 

 (1)類的構(gòu)造函數(shù)是private,阻止對象的建立;
 (2)GetSingleGameWorld函數(shù)被聲明為友元,避免了私有構(gòu)造函數(shù)引起的限制;
 (3)s_game_world為一個(gè)靜態(tài)對象,對象唯一。

當(dāng)用到CGameWorld的唯一實(shí)例化對象時(shí),可以如下:

GetSingleGameWorld().Init();
GetSingleGameWorld().Run();

如果有人對GetSingleGameWorld是一個(gè)全局函數(shù)有些不爽,或者不想使用友元,將其聲明為類CGameWorld的靜態(tài)函數(shù)也可以達(dá)到目的,如下:

class CGameWorld
{
public:
 bool Init();
 void Run();
 static CGameWorld& GetSingleGameWorld();
private:
 CGameWorld();
 CGameWorld(const CGameWorld& rhs);
};

這就是設(shè)計(jì)模式中著名的單件模式:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。

如果我們想讓對象產(chǎn)生的個(gè)數(shù)不是一個(gè),而是最大為N(N>0)個(gè)??梢栽陬悆?nèi)部設(shè)置一個(gè)靜態(tài)計(jì)數(shù)變量,在調(diào)用構(gòu)造函數(shù)時(shí),該變量加1,當(dāng)調(diào)用析構(gòu)函數(shù)時(shí),該變量減1。如下:

class CObject
{
public:
 CObject();
 ~CObject();
private:
 static size_t m_nObjCount;
 ...
};

CObject::CObject()
{
 if (m_nObjCount > N)
  throw;
 m_nObjCount++;
}

CObject::~CObject()
{
 m_nObjCount--;
}
size_t CObject::m_nObjCount;

掌握控制類的實(shí)例化對象個(gè)數(shù)的方法。當(dāng)實(shí)例化對象唯一時(shí),采用設(shè)計(jì)模式中的單件模式;當(dāng)實(shí)例化對象為N(N>0)個(gè)時(shí),設(shè)置計(jì)數(shù)變量是一個(gè)思路。

閱讀上面的示例代碼還需要注意拋出異常時(shí)沒有對象,即throw后沒有對象,有兩種含義: 

 (1)如果throw;在catch塊中或被catch塊調(diào)用的函數(shù)中出現(xiàn),表示重新拋出異常。throw;表達(dá)式將重新拋出當(dāng)前正在處理的異常。 我們建議采用該形式,因?yàn)檫@將保留原始異常的多態(tài)類型信息。重新引發(fā)的異常對象是原始異常對象,而不是副本。

(2)如果throw;出現(xiàn)在非catch塊中,表示拋出不能被捕獲的異常,即使catch(…)也不能將其補(bǔ)捕獲。

4.小結(jié)

堆對象,棧對象以及靜態(tài)對象統(tǒng)稱為內(nèi)存對象,如果要把內(nèi)存對象理解的更為深入,推薦看看《深入探索C++對象模型》這本書。

以上就是c++如何控制對象的創(chuàng)建方式(禁止創(chuàng)建棧對象or堆對象)和創(chuàng)建的數(shù)量的詳細(xì)內(nèi)容,更多關(guān)于c++控制對象的創(chuàng)建方式與數(shù)量的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言可變參數(shù)函數(shù)詳解

    C語言可變參數(shù)函數(shù)詳解

    在某些情況下我們希望函數(shù)的參數(shù)個(gè)數(shù)可以根據(jù)需要確定,因此c語言引入可變參數(shù)函數(shù)。典型的可變參數(shù)函數(shù)的例子有printf()、scanf()等,下面我就開始講解
    2021-08-08
  • VC取得任務(wù)欄高度的方法

    VC取得任務(wù)欄高度的方法

    這篇文章主要介紹了VC取得任務(wù)欄高度的方法,需要的朋友可以參考下
    2014-07-07
  • C++隱式類型轉(zhuǎn)換運(yùn)算符operator type()用法詳解

    C++隱式類型轉(zhuǎn)換運(yùn)算符operator type()用法詳解

    這篇文章主要介紹了C++隱式類型轉(zhuǎn)換運(yùn)算符operator type()用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • C++多態(tài)的實(shí)現(xiàn)及原理詳細(xì)解析

    C++多態(tài)的實(shí)現(xiàn)及原理詳細(xì)解析

    C++的多態(tài)性用一句話概括就是:在基類的函數(shù)前加上virtual關(guān)鍵字,在派生類中重寫該函數(shù),運(yùn)行時(shí)將會(huì)根據(jù)對象的實(shí)際類型來調(diào)用相應(yīng)的函數(shù)。如果對象類型是派生類,就調(diào)用派生類的函數(shù);如果對象類型是基類,就調(diào)用基類的函數(shù)
    2013-09-09
  • 通過實(shí)例詳解C語言函數(shù)返回值

    通過實(shí)例詳解C語言函數(shù)返回值

    函數(shù)的返回值是指函數(shù)被調(diào)用之后,執(zhí)行函數(shù)體中的程序段所取得的并返回給主調(diào)函數(shù)的值,下面這篇文章主要給大家介紹了關(guān)于C語言函數(shù)返回值的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • C++實(shí)現(xiàn)LeetCode(82.移除有序鏈表中的重復(fù)項(xiàng)之二)

    C++實(shí)現(xiàn)LeetCode(82.移除有序鏈表中的重復(fù)項(xiàng)之二)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(82.移除有序鏈表中的重復(fù)項(xiàng)之二),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • visual?studio?將編譯后的dll等文件自動(dòng)復(fù)制到指定目錄的方法

    visual?studio?將編譯后的dll等文件自動(dòng)復(fù)制到指定目錄的方法

    這篇文章主要介紹了visual?studio?將編譯后的dll等文件自動(dòng)復(fù)制到指定目錄,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • 詳解QTreeWidget隱藏節(jié)點(diǎn)的兩種方式

    詳解QTreeWidget隱藏節(jié)點(diǎn)的兩種方式

    本文主要介紹了QTreeWidget隱藏節(jié)點(diǎn)的兩種方式,一種是直接隱藏,一種是間接隱藏,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++中前綴和數(shù)組(算法)基本介紹

    C++中前綴和數(shù)組(算法)基本介紹

    前綴和(Prefix Sum)是指數(shù)組中某個(gè)位置之前的所有元素的和,本文將介紹C++中前綴和數(shù)組(算法)基本概念,感興趣的朋友一起看看吧
    2024-12-12
  • C語言如何輸出中文

    C語言如何輸出中文

    這篇文章主要介紹了C語言如何輸出中文問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論

浏阳市| 家居| 临颍县| 泸州市| 丰城市| 乐都县| 泌阳县| 霍州市| 新平| 渑池县| 凉山| 海兴县| 辽中县| 阜康市| 营山县| 珠海市| 乳山市| 博爱县| 襄汾县| 商河县| 西宁市| 怀来县| 广水市| 潮州市| 绥芬河市| 格尔木市| 元谋县| 临江市| 宜兴市| 阳东县| 漳平市| 翁源县| 奈曼旗| 同仁县| 福清市| 赣榆县| 武邑县| 邹平县| 无锡市| 南开区| 六枝特区|