在某些特殊场景,我们可能会希望一个类只能创建在堆上、不能被拷贝、不能被继承。
又或者我们希望一个类在main函数启动前就已经被实例化出来,并且我们不能再创建,这里就涉及到特殊类和单例模式。
阅读本文,将对你理解特殊类、单例模式有极大的帮助。
拷贝出现的场景只有拷贝构造和赋值。因此不能被拷贝的类必须禁用拷贝构造和赋值操作
C++98中:
1、设计为私有:防止用户在类外为函数定义
2、只声明不实现,会发生链接错误。不能完成编译。
C++11
delete关键字 删除默认成员函数(推荐写法)
//请设计一个类,该类不能发生拷贝
class copyban
{
public:
copyban(const copyban&) = delete;
copyban& operator=(const copyban&) = delete;
private:
};
这样就禁用拷贝构造和赋值运算符的生成
有俩种实现:
1、析构函数私有化
2、构造函数私有化
析构私有化,可行的原因:
C++是一个静态绑定的语言。在编译过程中,所有的非虚函数调用必须完成分析,即使是虚函数,也要检查可访问性。如果要在栈上生成对象,对象会自动调用构造和析构,也就是构造和析构必须可访问。否则编译错误。但是在堆上创建的对象,由于释放可以通过delete,所以在堆上的对象不一定要有析构函数。
class heaponly
{
public:
heaponly()
{
cout << "heaponly()" << endl;
}
void destory()
{
delete this;
}
private:
~heaponly()
{
cout << "~heaponly()" << endl;
}
};
int main()
{
heaponly *hp1 = new heaponly;
heaponly hp(*hp1);
return 0;
}
小细节:
????????由于析构的私有化,delete调不动析构函数,因此需要自定的destory函数完成清理工作
我们指定生成的对象在堆上
构造函数私有,不能通过普通定义来创建对象
禁用拷贝构造,防止用堆上的对象去构造栈上的对象
提供静态成员函数,用来创建堆上的对象
class HeapOnly
{
public:
static HeapOnly* CreateObj()
{
return new HeapOnly;
}
HeapOnly(const HeapOnly& hp) = delete;
private:
HeapOnly(){}
};
int main()
{
HeapOnly*hp= HeapOnly::CreateObj();
HeapOnly hp1(*hp);
return 0;
}
注意点:
1、构造私有
2、构造公有
私有构造函数,就不能在类外调用构造函数创建对象。因此需要类中提供静态的成员函数来提供对象的创建。
不能防止拷贝构造。new出来的对象可以赋值给变量。
如果禁用拷贝构造,则在对象创建后,返回值无法传递。
//请设计一个类,只能在栈上创建对象
//构造函数私有
class StackOnly
{
public:
static StackOnly CreatObj()
{
return StackOnly();
}
private:
StackOnly() {};
};
int main()
{
StackOnly sn = StackOnly::CreatObj();
StackOnly *sl = new StackOnly(sn);
return 0;
}
因此第一种方法并不能完全实现在栈上创建
把构造函数公有,operator new和delete禁掉?
class StackOnly
{
public:
StackOnly() {};
private:
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
};
int main()
{
StackOnly sn;
//StackOnly* sl = new StackOnly;
return 0;
}
这样子屏蔽了new的创建对象,但是依旧不发避免静态区创建的对象。
设计模式就是反复被人们使用,多人知晓的总结。
单例模式:一个类只能创建一次,该模式可以提供一个实例,并且提供全局的访问。
单例模式分为:
饿汉模式和懒汉模式
提前创建好对象,在main函数的启动时。
注意点:
class sigleton
{
public:
static sigleton* GetInstance()
{
return &m_instance;
}
private:
sigleton();
sigleton(const sigleton&) = delete;
sigleton& operator=(const sigleton&) = delete;
static sigleton m_instance;
int _a = 0;
};
sigleton sigleton::m_instance;
int main()
{
sigleton a();
return 0;
}
饿汉模式的优点:
实现简单
缺点:
启动慢,在程序启动时,会创建所有的单例对象,占用大量的时间。如果有多个单例,实例化的顺序无法确定。
解决了懒汉模式启动慢。耗费大量资源。懒汉模式是在调用时才会创建。
实现方法:
以饿汉模式为基础,懒汉模式类中的对象是指针,静态成员函数的返回值为一个new的指针
因此只有在调用时才会创建对象
资源是不需要释放的,因为在进程结束时,会自动回收。
如果需要做一些动作,比如持久化。可以利用gc的static托管。
class InfoMgr
{
public:
static InfoMgr* GetInstance()
{
if (_inst == nullptr)
{
_inst = new InfoMgr;
}
return _inst;
}
static void DelInstance()
{
if (_inst)
{
delete _inst;
_inst = nullptr;
}
}
private:
InfoMgr();
InfoMgr(const InfoMgr&) = delete;
InfoMgr& operator =(const InfoMgr&) = delete;
int _n = 0;
static InfoMgr* _inst;
class gc
{
public:
~gc()
{
DelInstance();
}
};
static gc _gc;
};
InfoMgr* InfoMgr::_inst = nullptr;
InfoMgr::gc InfoMgr::_gc;
优点:
启动快,由调动时才创建对象。可以确定顺序。
缺点:
实现复杂,多线程问题,加锁等问题。
本文共介绍了几种特殊类的实现
防止拷贝的类:
????C++98中私有,只声明不实现拷贝构造、赋值运算符。C++11 delete关键字删除拷贝构造和赋值
在堆上创建的类:
? ? ? ? 1)析构私有,需要实现destory。
????????2)构造私有,静态成员函数返回new对象指针 delete拷贝构造。
在栈上创建:
? ? ? ? 推荐构造公有,禁用operator new 和operator delete 缺点是静态区仍然可以创建
单例模式:
在类中创建静态成员对象,饿汉是对象,懒汉是对象指针
饿汉是在程序启动时就创建,懒汉是在首次调用时为空进入new创建对象。