目录
一.不能拷贝的类
首先要知道拷贝的场景:拷贝构造函数以及赋值运算符重载,想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
方法1:将这两个函数只声明,不定义(防止编译器默认生成,但不能防止用户可在外面定义),或者把这两个函数设置为私有。
方法2:C++11的方式将这两个函数删除(用delete)。
例如:
class Copyban
{
public:
Copyban()
:_a(99)
{
}
private:
//Copyban(Copyban&);
//Copyban& operator=(const Copyban&);
Copyban(Copyban&) = delete;
Copyban& operator=(const Copyban&) = delete;
int _a;
};
二.只能在堆上创建对象
class HeapOnly
{
public:
static HeapOnly* CreateObj()
{
return new HeapOnly;
}
private:
HeapOnly()
{}
HeapOnly(const HeapOnly&);
//HeapOnly(const HeapOnly&) = delete;
};
三.只能在栈上创建对象
class StackOnly
{
public:
static StackOnly CreateObj()
{
return StackOnly();
}
private:
//StackOnly(StackOnly&) = delete;
StackOnly()
{}
};
但无法防止在外面拷贝构造在创建对象。
StackOnly obj1 = StackOnly::CreateObj();
static StackOnly obj2(obj1); //在静态区拷贝构造对象
StackOnly* ptr = new StackOnly(obj1); //在堆上拷贝构造对象
方法2:
屏蔽operator new函数和operator delete函数,同时把构造函数私有化,用静态函数返回对象
new和delete默认调用的是全局的operator new函数和operator delete函数,但若是一个类重载了专属的operator new函数和operator delete函数,那么new和delete就会调用这个专属的函数。
例如:
class StackOnly
{
public:
static StackOnly CreateObj()
{
return StackOnly();
}
private:
StackOnly()
{}
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
//void* operator new(size_t size);
//void operator delete(void* p);
};
但依旧无法防止在静态区拷贝构造对象。
四.不能被继承的类
只要子类不能调用父类的构造函数即可。
方法1:
与前面类似,将构造函数私有化,用一个静态函数返回对象即可。
方法2:
用c++11的关键字,final,表示该类不能被继承。
例如:
class A final
{
// ....
};
五.只能创建一个对象(单例模式)
- 将构造函数设置为私有,并将拷贝构造函数和赋值运算符重载函数设置为私有或删除,防止外部创建或拷贝对象。
- 提供一个指向单例对象的static指针,并在程序入口之前完成单例对象的初始化。
- 提供一个全局访问点获取单例对象。
class Singleton
{
public:
//3、提供一个全局访问点获取单例对象
static Singleton* GetInstance()
{
return _inst;
}
private:
//1、将构造函数设置为私有,并防拷贝
Singleton()
{}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
//2、提供一个指向单例对象的static指针
static Singleton* _inst;
};
//在程序入口之前完成单例对象的初始化
Singleton* Singleton::_inst = new Singleton;
赋值重载是对于已经存在的对象,这里可以不做处理。
关于单例模式(饿汉实现)线程安全的问题:
饿汉模式是在程序运行主函数之前就完成了单例对象的创建,由于main函数之前是不存在多线程的,因此饿汉模式下单例对象的创建过程是线程安全的。后面访问这个对象是一个读的操作,也不会造成线程不安全。
懒汉模式:
- 将构造函数设置为私有,并将拷贝构造函数和赋值运算符重载函数设置为私有或删除,防止外部创建或拷贝对象。
- 提供一个指向单例对象的static指针,并在程序入口之前先将其初始化为空。
- 提供一个全局访问点获取单例对象。
例如:
在获取单例对象时进行加锁处理,防止多线程时创建多个对象。
class Singleton
{
public:
//3、提供一个全局访问点获取单例对象
static Singleton* GetInstance()
{
//加锁
if (_inst == nullptr)
{
_inst = new Singleton;
}
//解锁
return _inst;
}
private:
//1、将构造函数设置为私有,并防拷贝
Singleton()
{}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
//2、提供一个指向单例对象的static指针
static Singleton* _inst;
}
//在程序入口之前先将static指针初始化为空
Singleton* Singleton::_inst = nullptr;
static Singleton* GetInstance()
{
if (_inst == nullptr)
{
//加锁
if (_inst == nullptr)
{
_inst = new Singleton;
}
//解锁
}
return _inst;
}