1. 程式人生 > >C++ 私有建構函式的作用

C++ 私有建構函式的作用

       很多情況下要求當前的程式中只有一個object。例如一個程式只有一個和資料庫的連線,只有一個滑鼠的object。通常我們都將建構函式的宣告置於public區段,假如我們將其放入private區段中會發生什麼樣的後果?這意味著什麼?


      當我們在程式中宣告一個物件時,編譯器為呼叫建構函式(如果有的話),而這個呼叫將通常是外部的,也就是說它不屬於class物件本身的呼叫,假如建構函式是私有的,由於在class外部不允許訪問私有成員,所以這將導致編譯出錯。


      然而,對於class本身,可以利用它的static公有成員,因為它們獨立於class物件之外,不必產生物件也可以使用它們。


      此時因為建構函式被class私有化,所以我們要創建出物件,就必須能夠訪問到class的私有域;這一點只有class的成員可以做得到;但在我們建構出其物件之前,怎麼能利用它的成員呢?static公有成員,它是獨立於class物件而存在的,“我們”可以訪問得到。假如在某個static函式中建立了該class的物件,並以引用或者指標的形式將其返回(這裡不以物件返回,主要是建構函式是私有的,外部不能建立臨時物件),就獲得了這個物件的使用權。


      下面是例子:

class OnlyHeapClass
{
public:
   static OnlyHeapClass* GetInstance()
       {
              // 建立一個OnlyHeapClass物件並返回其指標
              return (new OnlyHeapClass);
       }
   void Destroy();
private:
       OnlyHeapClass() { }
       ~OnlyHeapClass() {}
};
int main()
{
       OnlyHeapClass *p = OnlyHeapClass::GetInstance();
       ... // 使用*p
       delete p;
       return 0;
}


      這個例子使用了私有建構函式,GetInstance()作為OnlyHeapClass的靜態成員函式來在記憶體中建立物件:由於要跨函式傳遞並且不能使用值傳遞方式,所以我們選擇在堆上建立物件,這樣即使getInstance()退出,物件也不會隨之釋放,可以手動釋放。
    
      建構函式私有化的類的設計保證了其他類不能從這個類派生或者建立類的例項,還有這樣的用途:例如,實現這樣一個class:它在記憶體中至多存在一個,或者指定數量個的物件(可以在class的私有域中新增一個static型別的計數器,它的初值置為0,然後在GetInstance()中作些限制:每次呼叫它時先檢查計數器的值是否已經達到物件個數的上限值,如果是則產生錯誤,否則才new出新的物件,同時將計數器的值增1.最後,為了避免值複製時產生新的物件副本,除了將建構函式置為私有外,複製建構函式也要特別宣告並置為私有。


      如果將建構函式設計成Protected,也可以實現同樣的目的,但是可以被繼承。

       另外如何保證只能在堆上new一個新的類物件呢?只需把解構函式定義為私有成員。
      原因是C++是一個靜態繫結的語言。在編譯過程中,所有的非虛擬函式呼叫都必須分析完成。即使是虛擬函式,也需檢查可訪問性。因些,當在棧上生成物件時,物件會自動析構,也就說解構函式必須可以訪問。而堆上生成物件,由於析構時機由程式設計師控制,所以不一定需要解構函式。保證了不能在棧上生成物件後,需要證明能在堆上生成它。這裡OnlyHeapClass與一般物件唯一的區別在於它的解構函式為私有。delete操作會呼叫解構函式。所以不能編譯。
       

      那麼如何釋放它呢?答案也很簡單,提供一個成員函式,完成delete操作。在成員函式中,解構函式是可以訪問的。當然detele操作也是可以編譯通過。 

void OnlyHeapClass::Destroy() { 
        delete this; 
} 


    建構函式私有化的類的設計可以保證只能用new命令在堆中來生成物件,只能動態的去建立物件,這樣可以自由的控制物件的生命週期。但是,這樣的類需要提供建立和撤銷的公共介面。


    另外過載delete,new為私有可以達到要求物件創建於棧上的目的,用placement new也可以建立在棧上。

---------------------------------------------------------------------------------------------------------------------------------
還是不懂啊:   
  1.為什麼要自己呼叫呢?物件結束生存期時不就自動呼叫析構函數了嗎?什麼情況下需要自己呼叫解構函式呢?   
  ================================================================   
  比如這樣一種情況,你希望在析構之前必須做一些事情,但是用你類的人並不知道,    那麼你就可以重新寫一個函式,裡面把要做的事情全部做完了再呼叫解構函式。   這樣人家只能呼叫你這個函式析構物件,從而保證了析構前一定會做你要求的動作。   
    
  2.什麼情況下才用得著只生成堆物件呢?   
  ================================   
  堆物件就是new出來的,相對於棧物件而言。什麼情況下要new,什麼情況下在棧裡面    提前分配,無非就是何時該用動態,何時該用靜態生成的問題。這個要根據具體情況   
  具體分析。比如你在一個函式裡面事先知道某個物件最多隻可能10個,那麼你就可以定義這個物件的一個數組。10個元素,每個元素都是一個棧物件。如果你無法確定數字,那麼你就可以定義一個這個物件的指標,需要建立的時候就new出來,並且用list   或者vector管理起來。   

---------------------------------------------------------------------------------------------------------------------------------
類中“私有”許可權的含義就是:私有成員只能在類域內被訪問,不能在類域外進行訪問。   
    
  把解構函式定義為私有的,就阻止了使用者在類域外對解構函式的使用。這表現在如下兩個方面:   
    
  1.   禁止使用者對此型別的變數進行定義,即禁止在棧記憶體空間內建立此型別的物件。要建立物件,只能用   new   在堆上進行。  
    
  2.   禁止使用者在程式中使用   delete   刪除此型別物件。物件的刪除只能在類內實現,也就是說只有類的實現者才有可能實現對物件的   delete,使用者不能隨便刪除物件。如果使用者想刪除物件的話,只能按照類的實現者提供的方法進行。   
    
  可見,這樣做之後大大限制了使用者對此類的使用。一般來說不要這樣做;

   通常這樣做是用來達到特殊的目的,比如在   singleton(單例設計模式)   的實現上,可查詢   singleton   的資料來了解它是怎麼一回事。
--------------------- 
作者:koudaidai 
來源:CSDN 
原文:https://blog.csdn.net/koudaidai/article/details/7546661 
版權宣告:本文為博主原創文章,轉載請附上博文連結!