这几天涉及到禁止类的拷贝与赋值,所以来写一下相关的东西。如有错漏,还望指摘。
首先,如果未定义构造函数、拷贝函数和赋值操作符的时候,C++会为类自动生成默认版本的。如果想禁止类的拷贝、赋值,甚至构造,有两种方法。
- 将其设为私有。
这种方法很简单,就是写一个拷贝构造函数、赋值操作符,然后将其放在private限定符下。这样当外部想要拷贝或者赋值时,就会发现这个是私有的,禁止访问。
使用这种方法时,函数本身仍是存在的,只是访问被限定了。此时于类的内部仍然可以进行拷贝或者赋值。所以当你仍然需要拷贝或者赋值,只是禁止从外部进行时,可以使用这种方式。
示例:class Test { private: Test(const Test&) {}; Test& operator = (const Test&) { cout << "assign" << endl; return *this; } public: Test() {}; static void makeACopy(Test& left, const Test& right){ left = right; } } int main(){ Test a; //成功 Test b = a; //失败,拷贝函数不可访问 Test c(a); //失败,拷贝函数不可访问 Test d; d = a; //失败,赋值操作符禁止访问 Test::makeACopy(d,a); //成功,在类内可以进行赋值 }
- 使用delete关键字
使用delete关键字可以禁止函数的生成。此时无论从外部还是内部,都禁止对该函数的调用。好处是放在什么限定符下都可以,无论是private抑或是public。这样在将其定义成宏时,无需定义限定符,不用担心使用宏之后还需要重新定义限定符。
示例class Test{ public: Test() {}; Test(const Test&) = delete; Test& operator = (const Test&) = delete; } int main(){ Test a; //成功 Test b = a; //失败,它是已删除的函数 Test c(a); //失败,它是已删除的函数 Test d; d = a; //失败,赋值操作符禁止访问 }
这两种方法的优缺点涉及到接下来说的单例模式。
单例模式
所谓单例模式,就是说只能有一个实例存在。通常使用的方法是,由类内负责实例的生成,而禁止类外构造。
示例如下:
#define DISALLOW_COPY_AND_ASSIGN(class_name) \
class_name(const class_name&) = delete;\
class_name& operator = (const class_name&) = delete;
class Singleton{
private:
//此时只能使用第一种方法,因为在类内我们仍然需要调用构造函数
//我们只是禁止类外进行构造
Singleton(arg) {};
public:
//此时使用第二种方法禁止拷贝构造函数和赋值操作符
//使得使用宏时,无须担心之后的函数会变成私有
DISALLOW_COPY_AND_ASSIGN(Singleton)
static Singleton* getInstance(arg){
static Singleton instance(arg);
return &instance;
}
}
此时构造函数为私有,所以禁止类外构造。类外只能通过静态函数getInstance来获取唯一一个的静态实例。另外,使用静态变量的好处是,类外无需再关心什么时候析构这个类。静态变量随着程序的结束自动进行析构。但是需要注意的是!因为返回的是指针,所以类外可以进行手动析构,但是这会导致程序结束时发生错误。