c++ 單例模式 友元函式
一.設計模式
- 單例模式(類只能生成一個物件)
- 遮蔽建構函式,拷貝建構函式(放在private中 類外無法訪問),此時類外就無法看到這兩個函數了 也就無法生成物件了 類就沒有意義了
- 類中給出一個介面(getInstance) 生成唯一物件 返回值為類型別的指標或引用(不生成其他物件) 如果為類型別返回 則會有臨時物件產生 此時就不叫單例模式了
①返回值不能返回類型別(會有臨時物件產生)
②這個介面一定要不依賴物件(因為這個介面是要生成物件的 如果依賴物件 則無法生成物件) 因此要加static關鍵字
程式碼如下:
class SingleTon
{
public:
static SingleTon* getInstance()//類中給出一個介面getInstance生成唯一物件返回值為類型別的指標或引用 同時這個介面不依賴物件因此加上static的關鍵字
{
return &single;
}
private:
SingleTon(){};
SingleTon(const SingleTon&);//遮蔽拷貝建構函式(防止生成新物件)
static SingleTon single;
};
SingleTon SingleTon::single;//static修飾的成員要在類外初始化
int main()
{
SingleTon* psingle1 = SingleTon::getInstance();
SingleTon* psingle2 = SingleTon::getInstance();
SingleTon* psingle3 = SingleTon::getInstance();
SingleTon* psingle4 = SingleTon::getInstance();
return 0;
}
執行緒安全問題
- 此時執行緒不安全則要加鎖
class SingleTon
{
public:
static SingleTon* getInstance()
{
//lock();
if (psingle == NULL)
{
psingle = new SingleTon();
}
//unlock();
return psingle;
}
此時A執行緒執行完了 加鎖解鎖後 B執行緒才能執行 但效率很低 不管物件是否存在都會加鎖解鎖
- 雙重鎖機制的單例模式
當有物件生成的時候 直接返回物件 就不用加鎖解鎖了
在main函式之前就生成物件就不存線上程安全的問題了 因為執行緒在main中才執行
程式碼如下:
class SingleTon
{
public:
static SingleTon* getInstance()
{
if (psingle == NULL)//當有物件生成的時候 直接返回物件
{
//lock();
if (psingle == NULL)
{
psingle = new SingleTon();
}
//unlock();
}
return psingle;
}
private:
SingleTon(){}
SingleTon(const SingleTon&);
static SingleTon* psingle;//指向物件的指標 static修飾的並不屬於物件 屬於類作用域
};
SingleTon* SingleTon::psingle = NULL;
二.友元函式
在C++中,我們使用類對資料進行了隱藏和封裝,類的資料成員一般都定義為私有成員,成員函式一般都定義為公有的,以此提供類與外界的通訊介面。但是,有時需要定義一些函式,這些函式不是類的一部分,但又需要頻繁地訪問類的資料成員,這時可以將這些函式定義為該函式的友元函式。除了友元函式外,還有友元類,兩者統稱為友元。友元的作用是提高了程式的執行效率(即減少了型別檢查和安全性檢查等都需要時間開銷),但它破壞了類的封裝性和隱藏性,使得非成員函式可以訪問類的私有成員。
友元類 :將外界的某個類在本類別的定義中說明為友元,那麼外界的類就成為本類的“朋友”,那個類就可以訪問本類的私有資料了。友元類的所有成員函式都是另一個類的友元函式,都可以訪問另一個類中的隱藏資訊(包括私有成員和保護成員)。
當希望一個類可以存取另一個類的私有成員時,可以將該類宣告為另一類的友元類。定義友元類的語句格式如下:
friend class 類名;
其中:friend和class是關鍵字,類名必須是程式中的一個已定義過的類。
例如,以下語句說明類B是類A的友元類:
class A
{
…
public:
friend class B;
…
};
經過以上說明後,類B的所有成員函式都是類A的友元函式,能存取類A的私有成員和保護成員。
使用友元類時注意:
(1) 友元關係不能被繼承。
(2) 友元關係是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的宣告。
(3) 友元關係不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明
《windows環境多執行緒程式設計原理與應用》中解釋:
如果將類的封裝比喻成一堵牆的話,那麼友元機制就像牆上了開了一個門,那些得
到允許的類或函式允許通過這個門訪問一般的類或者函式無法訪問的私有屬性和方
法。友元機制使類的封裝性得到消弱,所以使用時一定要慎重。
友元關係有三種:
- 函式友元 (cdecal)
- 類友元 (thiscall)
- 類成員方法的友元
只有你賦予某個類為你的友元時,那個類才有訪問你的私有資料的權利。說明一個函式為一個類的友元函式則該函式可以訪問此類的私有資料和方法。定義方法是在類的定義中,在函式名前加上關鍵字friend.
友元函式的優缺點:
優點:打破了封裝性 通常對於普通函式來說,要訪問類的保護成員是不可能的,如果想這麼做那麼必須把類的成員都生命成為public(共用的),然而這做帶來的問題遍是任何外部函式都可以毫無約束的訪問它操作它,c++利用friend修飾符,可以讓一些你設定的函式能夠對這些保護資料進行操作,避免把類成員全部設定成public,最大限度的保護資料成員的安全。
缺點:友元能夠使得普通函式直接訪問類的保護資料,避免了類成員函式的頻繁呼叫,可以節約處理器開銷,提高程式的效率,但所矛盾的是,即使是最大限度大保護,同樣也破壞了類的封裝特性,這即是友元的缺點,在現在cpu速度越來越快的今天我們並不推薦使用它,但它作為c++一個必要的知識點,一個完整的組成部分,我們還是需要討論一下的。 在類裡宣告一個普通數學,在前面加上friend修飾,那麼這個函式就成了該類的友元,可以訪問該類的一切成員。
因此建議:能不用友元就不用友元 不得不用的時候在用友元