1. 程式人生 > >類的巢狀以及類的私有建構函式

類的巢狀以及類的私有建構函式

在C++中“類的巢狀”以及“私有建構函式”是不是大家都不常用啊?下面先看一個例子吧:

#include <iostream> usingnamespace std; template< typename T > //注意一點static成員是獨立於類而存在的。 class Singleton { //類的巢狀定義 class InstanceHolder     { public:         InstanceHolder() : mObject(0) {}         ~InstanceHolder() { delete mObject; }         T* 
set(T* p) { delete mObject; mObject = p;return mObject; } private:         T* mObject;     }; public: //這裡也是用的static static T* instance()     { return mInstance.set(new T());     } private: //這裡定義了私有的建構函式     Singleton(); //巢狀定義類的例項,注意這裡是在private裡面,而且用的是static static InstanceHolder           mInstance;
}; //下面兩句要看清楚啊!!!瞭解typename的用法(詳見下一篇) //初始化static成員,是不是看起來有些彆扭啊,如果你知道了typename的用法就會 //明白下面兩句的意思了 template< typename T > typename Singleton<T>::InstanceHolder Singleton<T>::mInstance; class        ServiceListener { public: virtual ~ServiceListener()         { } virtualvoid serviceStarted() = 0;
virtualvoid serviceStopped() = 0; }; void ServiceListener::serviceStarted() {         printf("serviceStarted() event listener is not implemented."); } void ServiceListener::serviceStopped() {         printf("serviceStarted() event listener is not implemented."); } class ServiceController; typedef Singleton<ServiceController> ServiceKontrol; class ServiceController : public ServiceListener { public:         ServiceController();         ~ServiceController(); virtualvoid serviceStarted(); virtualvoid serviceStopped(); private: bool started; }; ServiceController::ServiceController() : started(false) { } ServiceController::~ServiceController() { } void ServiceController::serviceStarted() {         printf("service start/n"); } void ServiceController::serviceStopped() {         printf("servicestop/n"); } int main(int argc, char **argv) { int num=0; //因為一開始在類的宣告中就將instance()宣告為static, //所以它可以不例項化Singleton類,而直接呼叫         ServiceKontrol::instance()->serviceStarted();         ServiceController test;         test.serviceStarted(); //下面這句是不會定義成功的,因為它的建構函式是private的 //      ServiceKontrol isok;         std::cin >> num; return 0; }

上面的例子看的怎麼樣?是不是有些迷糊啊,呵呵,有些東西之所以難是因為你並沒有真正瞭解它!好,讓我們先理論知識吧:

C++ 類的建構函式一般是public的,但是也可以是private的。
類中定義了私有建構函式後:

1. 不能例項化:因為例項化時,類外部無法訪問其內部的私有建構函式;

2. 不能繼承: 理由與1相同。

通常我們都將建構函式的宣告置於public區段,假如我們將其放入private區段中會發生什麼樣的後果?沒錯,我也知道這將會使建構函式成為私有的,這意味著什麼?

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

你於是說:“哈哈。”我們製造了一個似乎無法產生物件的class.哦,當然,對於class本身,我們還可以利用它的static公有成員,因為它們獨立於class物件之外,我們不必產生物件也可以使用它們。嗯,看來我們還是為帶有私有建構函式的類找到了一個存在的理由。不過我們不應當滿足於此,因為看上去應當還有發掘的餘地。

首先我們來認真看一下是不是真的無法創建出一個具有私有建構函式的類物件。“呃,可能未必。”你現在也許會這樣說。這很好,讓我們再來看看為什麼,沒錯,因為建構函式被class私有化了,所以我們要創建出物件,就必須能夠訪問到class的私有域;但這一點“我們”是做不到的,那麼,誰能做得到呢?class的成員可以做得到;但在我們建構出其物件之前,怎麼能利用它的成員呢?噢,剛才我們剛剛提到了static公有成員,它是獨立於class物件而存在的,當然,它也是公有的,“我們”可以訪問得到。假如在某個static函式中建立了該class的物件,並以引用或者指標的形式將其返回(不可以以值的形式返回,想想為什麼),我們就獲得了這個物件的使用權。下面是例子:

class WonderfulClass { public: static WonderfulClass* makeAnObject()        { // 建立一個WonderfulClass物件並返回其指標 return (new WonderfulClass);        } private:        WonderfulClass() { } }; int main() {        WonderfulClass *p = WonderfulClass::makeAnObject();        ... // 使用*p        delete p;  // Not neccesary here, but it's a good habit. return 0; }

嗯,這個例子使用了私有建構函式,但它執行得很好:makeAnObject()作為WonderfulClass的靜態成員函式,盡心盡責地為我們建立物件:由於要跨函式傳遞並且不能使用值傳遞方式,所以我們選擇在堆上建立物件,這樣即使退出,物件也不會隨之蒸發掉,當然,使用完之後你可不要忘了手工將它清除。

回到前面的思路:除了公有的static成員可以幫助我們訪問私有域外,還有沒有其它可以利用的東西?

噢,你一定想到了使用友元,完全正確。可以使用該類的友元函式或者友元類建立其物件,這裡就不舉例了。

我們知道沒有人會無聊到無緣無故把一個設為私有,然後再寫一個和上面一模一樣的makeAnObject()來讓它的使用者體驗一下奇特的感覺。我們也不太相信這只是由於C++的設計原因而導致的一個順便的、特殊的、無用的、邊角功能。它應當是有實際用途的。提醒一下,到了JAVA中你會更容易明白很多靜態方法建立物件的原理!!!

嗯,例如,我們想實現這樣一個class:它至多隻能存在一個,或者指定數量個的物件還記得標準輸入輸出流庫中那個獨一無二的嗎?),我們可以在class的私有域中新增一個static型別的計數器,它的初值置為0,然後再對makeAnObject()做點手腳:每次呼叫它時先檢查計數器的值是否已經達到物件個數的上限值,如果是則產生錯誤,否則才new出新的物件,同時將計數器的值增1.最後,為了避免值複製時產生新的物件副本,除了將建構函式置為私有外,複製建構函式也要特別宣告並置為私有。