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
,表示该类不可被继承。