1.設計不能被拷貝的類
解析:拷貝只會放生在兩個場景中
- 拷貝構造函數
- 賦值運算符重載
因此想要讓一個類禁止拷貝, 就需讓該類不能調用“拷貝構造函數”以及“賦值運算符重載”,而
C++11
提供的delete
重載關鍵字可以讓這件事情變得更加簡單。
1.1.C++98做法
class CopyBan
{
public:CopyBan(): _c(1) {}private://拷貝構造私有化CopyBan(const CopyBan&);//賦值重載私有化CopyBan& operator=(const CopyBan&);private:int _c;
};int main()
{CopyBan c;//CopyBan copy(c);//禁用了return 0;
}
1.2.C++11做法
class CopyBan
{
public:CopyBan(): _c(1) {}//拷貝構造私有化CopyBan(const CopyBan&) = delete;//賦值重載私有化CopyBan& operator=(const CopyBan&) = delete;private:int _c;
};int main()
{CopyBan c;//CopyBan copy(c);//禁用了return 0;
}
2.設計在堆上創建的類
2.1.析構私有
解析:一個在棧上的對象如果沒有辦法調用析構,就沒有辦法被創建,因為編譯器認為沒有析構,禁止直接創建對象,這種情況就只能使用
new
創建對象,并且提供一個用于釋放的接口。
class HeapOnly
{
public:static void Destroy_1(HeapOnly* ptr){delete ptr;}//orvoid Destroy_2(){delete this;}private:~HeapOnly() {}
};int main()
{//HeapOnly h1;//禁用HeapOnly* ph1 = new HeapOnly;HeapOnly::Destroy_1(ph1);HeapOnly* ph2 = new HeapOnly;ph2->Destroy_2();//HeapOnly h2(*ph1);//禁用return 0;
}
2.2.構造私有
解析:如果一個類的構造被私有了,那么就無法直接調用,包括
new
也無法調用,然后我們提供給用戶一個接口,在類的內部new
返回類指針給用戶,交給用戶釋放即可。就是需要注意,還需要將拷貝構造私有化,避免用戶使用接口后,解引用進行拷貝。
class HeapOnly
{
public:static HeapOnly* CreateObject()//這里必須是 static 靜態成員函數{return new HeapOnly;}private:HeapOnly() {}HeapOnly(const HeapOnly&);
};int main()
{//HeapOnly h1;//禁用HeapOnly* ph = HeapOnly::CreateObject();//如果不是靜態就需要創建對象來調用 CreateObject(),但我們已經沒有辦法產生對象了//HeapOnly h2(*ph);//禁用return 0;
}
3.設計在棧上創建的類
解析:需要刪除
operator new()
才能徹底解決問題,注意不能私有構造函數!
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}//禁掉 operator new() 可以把用 new 調用拷貝構造申請對象給禁掉void* operator new(size_t size) = delete;void operator delete(void* p) = delete;private:StackOnly()//實際上刪除了 operator new() 就無需將構造函數私有化了,上述的 CreateObj() 也可以一起不要了: _a(0){}//不可私有拷貝構造//StackOnly(StackOnly& s)// : _a(0)//{}private:int _a;
};int main()
{StackOnly obj = StackOnly::CreateObj();//StackOnly* ptr1 = new StackOnly();//禁用//StackOnly* ptr2 = new StackOnly(obj);//禁用,這個不能私有拷貝構造,只能刪除 new 的底層調用 operator new,否則就無法返回 CreateObj() 的結果//delete& obj;//禁用return 0;
}
4.設計無法被繼承的類
4.1.C++98做法
父類的構造函數被私有化就不會被子類繼承。
4.2.C++11做法
使用關鍵字final
,表示該類不可被繼承。