C++特殊類設(shè)計(單例模式)
1.請設(shè)計一個類,不能被拷貝
-
C++98
將拷貝構(gòu)造函數(shù)與賦值運算符重載只聲明不定義,并且將其訪問權(quán)限設(shè)置為私有即可。class CopyBan { ? ?// ...? ? private: ? ?CopyBan(const CopyBan&); ? ?CopyBan& operator=(const CopyBan&); ? ?//... };
原因:
-
設(shè)置成私有:如果只聲明沒有設(shè)置成private,用戶自己如果在類外定義了,就可以不能禁止拷貝了
-
只聲明不定義:不定義是因為該函數(shù)根本不會調(diào)用,定義了其實也沒有什么意義,不寫反而還簡單,而且如果定義了就不會防止成員函數(shù)內(nèi)部拷貝了。
-
-
C++11C++11擴展delete的用法,delete除了釋放new申請的資源外,如果在默認(rèn)成員函數(shù)后跟上=delete,表示讓編譯器刪除掉該默認(rèn)成員函數(shù)。
class CopyBan { ? ?// ... ? ?CopyBan(const CopyBan&)=delete; ? ?CopyBan& operator=(const CopyBan&)=delete; ? ?//... };
2. 請設(shè)計一個類,只能在堆上創(chuàng)建對象
實現(xiàn)方式:
- 將類的構(gòu)造函數(shù)私有,拷貝構(gòu)造聲明成私有。防止別人調(diào)用拷貝在棧上生成對象。
- 提供一個靜態(tài)的成員函數(shù),在該靜態(tài)成員函數(shù)中完成堆對象的創(chuàng)建
//請設(shè)計一個類,只能在堆上創(chuàng)建對象
//思路1
class HeapOnly
{
public:
void Destroy()
{
delete this;
}
private:
~HeapOnly()
{
cout << "~HeapOnly()" << endl;
}
int _x;
};
//思路2
class HeapOnly2
{
public:
static HeapOnly2* CreateObj(int x = 0)
{
return new HeapOnly2(x);
}
private:
HeapOnly2(int x=0)
:_x(x)
{}
HeapOnly2(const HeapOnly2& hp) = delete;
HeapOnly2& operator=(const HeapOnly2& hp) = delete;
int _x;
};
3. 請設(shè)計一個類,只能在棧上創(chuàng)建對象
將構(gòu)造函數(shù)私有化,然后設(shè)計靜態(tài)方法創(chuàng)建對象返回即可。
//請設(shè)計一個類,只能在棧上創(chuàng)建對象
class StackOnly
{
public:
static StackOnly CreateObj(int x = 0)
{
return StackOnly(x);
}
StackOnly(StackOnly&& so)
:_x(so._x)
{}
private:
StackOnly(int x = 0)
:_x(x)
{}
StackOnly(const StackOnly& so) = delete;
int _x;
};
4. 請設(shè)計一個類,不能被繼承
-
C++98
// C++98中構(gòu)造函數(shù)私有化,派生類中調(diào)不到基類的構(gòu)造函數(shù)。則無法繼承 class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit() {} };
-
C++11
final關(guān)鍵字,final修飾類,表示該類不能被繼承。class A ?final { ? ?// .... };
5.請設(shè)計一個類,只能創(chuàng)建一個對象(單例模式)
設(shè)計模式:
設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類的、代碼設(shè)計經(jīng)驗的總結(jié)。
使用設(shè)計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設(shè)計模式使代碼編寫真正工程化;設(shè)計模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。
單例模式:
一個類只能創(chuàng)建一個對象,即單例模式,該模式可以保證系統(tǒng)中該類只有一個實例,并提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。比如在某個服務(wù)器程序中,該服務(wù)器的配置信息存放在一個文件中,這些配置數(shù)據(jù)由一個單例對象統(tǒng)一讀取,然后服務(wù)進程中的其他對象再通過這個單例對象獲取這些配置信息,這種方式簡化了在復(fù)雜環(huán)境下的配置管理。
單例模式有兩種實現(xiàn)模式:
餓漢模式
就是說不管你將來用不用,程序啟動時就創(chuàng)建一個唯一的實例對象。
//餓漢模式:第一次訪問實例對象前創(chuàng)建
// 餓漢模式
// 優(yōu)點:簡單
// 缺點:可能會導(dǎo)致進程啟動慢,且如果有多個單例類對象實例啟動順序不確定。
class Singleton
{
public:
static Singleton* GetInstance()
{
return _ins;
}
void Add(const string& str)
{
mtx.lock();
_v.push_back(str);
++_n;
mtx.unlock();
}
void Print()
{
mtx.lock();
for (auto e : _v)
cout << e << endl;
mtx.unlock();
}
int getN()
{
return _n;
}
private:
//限制類外面隨意創(chuàng)建對象
Singleton()
{}
private:
int _n = 0;
mutex mtx;
vector<string> _v;
static Singleton* _ins;
};
Singleton* Singleton::_ins = new Singleton;
如果這個單例對象在多線程高并發(fā)環(huán)境下頻繁使用,性能要求較高,那么顯然使用餓漢模式來避免資源競爭,提高響應(yīng)速度更好。
懶漢模式
如果單例對象構(gòu)造十分耗時或者占用很多資源,比如加載插件啊, 初始化網(wǎng)絡(luò)連接啊,讀取文件啊等等,而有可能該對象程序運行時不會用到,那么也要在程序一開始就進行初始化,就會導(dǎo)致程序啟動時非常的緩慢。 所以這種情況使用懶漢模式(延遲加載)更好。
// 懶漢
// 優(yōu)點:第一次使用實例對象時,創(chuàng)建對象。進程啟動無負(fù)載。多個單例實例啟動順序自由控制。
// 缺點:復(fù)雜
class Singleton
{
public:
static Singleton* GetInstance()
{
//雙檢查加鎖
if (_ins == nullptr) //提高效率,不需要每次獲取單例都加鎖解鎖
{
_imtx.lock();
if (_ins == nullptr) //保證線程安全和只new一次
_ins = new Singleton;
_imtx.unlock();
}
return _ins;
}
//一般全局都要使用單例對象,所以單例對象一般不需要顯示釋放
//有些特殊場景,想顯示釋放一下
static void DelInstance()
{
_imtx.lock();
if (_ins)
{
delete _ins;
_ins = nullptr;
}
_imtx.unlock();
}
~Singleton()
{
cout << "~Singleton()" << endl;
//持久化
//比如要求程序結(jié)束時,將數(shù)據(jù)寫到文件,單例對象析構(gòu)時持久化就比較好
}
//內(nèi)部類:單例對象回收
class GC
{
public:
~GC()
{
DelInstance();
}
};
void Add(const string& str)
{
mtx.lock();
//_v.push_back(str);
++_n;
mtx.unlock();
}
void Print()
{
mtx.lock();
for (auto e : _v)
cout << e << endl;
mtx.unlock();
}
int getN()
{
return _n;
}
private:
//限制類外面隨意創(chuàng)建對象
Singleton()
{}
Singleton(const Singleton& sl) = delete;
Singleton& operator=(const Singleton& sl) = delete;
private:
int _n = 0;
mutex mtx;
vector<string> _v;
static Singleton* _ins;
static mutex _imtx;
static GC _gc;
};
Singleton* Singleton::_ins = nullptr;
mutex Singleton::_imtx;
Singleton::GC Singleton::_gc;
分析:懶漢和餓漢的優(yōu)缺點
餓漢的缺點:
1.如果單例對象初始化很慢(如初始化動作多,還會伴隨一些IO行為,如讀取配置文件),main函數(shù)之前就要申請,第一,暫時不需要使用確占用資源,第二程序啟動會受影響。
2.如果兩個單例都是餓漢,并且有依賴關(guān)系,要求單例1再創(chuàng)建,單例2再創(chuàng)建,餓漢無法控制順序,懶漢才可以。
餓漢的優(yōu)點:
簡單(相對懶漢而言)文章來源:http://www.zghlxwxcb.cn/news/detail-805486.html
懶漢完美的解決了上面餓漢的問題,就是相對復(fù)雜一點文章來源地址http://www.zghlxwxcb.cn/news/detail-805486.html
到了這里,關(guān)于C++特殊類設(shè)計(單例模式)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!