在C++中“類的嵌套”以及“私有構造函數”是不是大家都不常用啊?下面先看一個例子吧:
#include <iostream>
using namespace std;
template< typename T >
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 T* instance()
{
return mInstance.set(new T());
}
private:
Singleton();
static InstanceHolder mInstance;
};
template< typename T >
typename Singleton<T>::InstanceHolder Singleton<T>::mInstance;
class ServiceListener
{
public:
virtual ~ServiceListener()
{ }
virtual void serviceStarted() = 0;
virtual void 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();
virtual void serviceStarted();
virtual void 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;
ServiceKontrol::instance()->serviceStarted();
ServiceController test;
test.serviceStarted();
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()
{
return (new WonderfulClass);
}
private:
WonderfulClass() { }
};
int main()
{
WonderfulClass *p = WonderfulClass::makeAnObject();
...
delete p;
return 0;
}
嗯,這個例子使用了私有構造函數,但它運行得很好:makeAnObject()作爲WonderfulClass的靜態成員函數,盡心盡責地爲我們創建對象:由於要跨函數傳遞並且不能使用值傳遞方式,所以我們選擇在堆上創建對象,這樣即使退出,對象也不會隨之蒸發掉,當然,使用完之後你可不要忘了手工將它清除。
回到前面的思路:除了公有的static成員可以幫助我們訪問私有域外,還有沒有其它可以利用的東西?
噢,你一定想到了使用友元,完全正確。可以使用該類的友元函數或者友元類創建其對象,這裏就不舉例了。
我們知道沒有人會無聊到無緣無故把一個設爲私有,然後再寫一個和上面一模一樣的makeAnObject()來讓它的用戶體驗一下奇特的感覺。我們也不太相信這只是由於C++的設計原因而導致的一個順便的、特殊的、無用的、邊角功能。它應當是有實際用途的。提醒一下,到了JAVA中你會更容易明白很多靜態方法創建對象的原理!!!
嗯,例如,我們想實現這樣一個class:它至多隻能存在一個,或者指定數量個的對象還記得標準輸入輸出流庫中那個獨一無二的嗎?),我們可以在class的私有域中添加一個static類型的計數器,它的初值置爲0,然後再對makeAnObject()做點手腳:每次調用它時先檢查計數器的值是否已經達到對象個數的上限值,如果是則產生錯誤,否則才new出新的對象,同時將計數器的值增1.最後,爲了避免值複製時產生新的對象副本,除了將構造函數置爲私有外,複製構造函數也要特別聲明並置爲私有。