1.不能被拷贝的类
如果想让一个类不能被拷贝,只需要禁掉这个类的拷贝构造和赋值运算符的重载即可。在C++11中我们可以用delete关键字来隐式删除这两个函数。
class CopyBan
{
// ...
CopyBan(const CopyBan&)=delete;
CopyBan& operator=(const CopyBan&)=delete;
//...
};
2.只能在堆上创建对象的类
只能在堆上创建也就是只能通过new或者malloc等方式创建对象。实现方式为以下两个步骤:
1.首先将构造函数私有,其次为了方式通过拷贝构造的方式在栈上创建对象,拷贝构造也要私有。
2.提供一个静态的成员函数,在这个静态的成员函数中创建对象。(在堆上)
class HeapOnly
{
public:
static HeapOnly* CreateObject()
{
return new HeapOnly;
}
private:
HeapOnly() {}
// C++98
// 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要
// 2.声明成私有
HeapOnly(const HeapOnly&);
// C++11的实现方式
HeapOnly(const HeapOnly&) = delete;
};
3.只能在栈上创建对象的类
只能在栈上创建也就是不能用new等关键字。我们可以直接把new和delete的重载禁掉,同样也是提供一个静态成员函数,在这个函数里创建对象。
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()
:_a(0)
{}
int _a;
};
4.不能被继承的类
在C++98中,我们需要把构造函数私有,因为子类创建对象需要先调用父类的构造函数,父类构造函数私有子类就调用不到。
但是在C++11中有更简便的方法,我们可以直接使用final关键字。
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:
static NonInherit GetInstance()
{
return NonInherit();
}
private:
NonInherit()
{}
};
//C++11超简洁
class A final
{
// ....
};
5.只能创建一个对象的类(单例模式)
设计模式
单例模式
单例模式也就是这个类只能创建一个对象。单例模式有两种实现方式:
1.饿汉模式
简单来说就是不管这个对象用不用,程序启动时就给它创建好了(就是在main函数调用前)。优点是简单。缺点是程序启动会变慢。
其实程序启动变慢在公司当中还是比较坑的。因为慢的话启动时间可能会有几十分钟,慢的话一是程序猿内心的煎熬,二是我们也不知道这个程序是启动慢还是已经挂了,三是启动慢的话也确实没那么好用。四就是它可能还用不到。
饿汉模式还有一个缺点就是如果有两个类相互依赖,那么就需要明确这两个对象的创建顺序,但是这个是不好控制,所以在这个场景下耦合度过高。
实现方法,也是将构造函数私有,并且再定义一个静态成员函数,在这个函数中返回我们一开始就创建好的对象的地址。
// 饿汉模式
// 优点:简单
// 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
class Singleton
{
public:
static Singleton* GetInstance()
{
return &m_instance;
}
private:
// 构造函数私有
Singleton(){};
// C++98 防拷贝
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
// 或者用
// C++11
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
static Singleton m_instance;
};
Singleton Singleton::m_instance; // 在程序入口之前就完成单例对象的初始化
2.懒汉模式
这个是饿汉模式的优化版,相比饿汉模式,它不会程序一启动就把对象创建好,而是当我们调用的时候再创建。
大致思想就是在我们调用这个静态的成员函数时,在这个函数里创建对象并返回,同时要避免反复创建。它优点就是解决了饿汉的缺点,缺点就是比较复杂。
namespace lazy
{
class Singleton
{
public:
// 2、提供获取单例对象的接口函数
static Singleton& GetInstance()
{
if (_psinst == nullptr)
{
// 第一次调用GetInstance的时候创建单例对象
_psinst = new Singleton;
}
return *_psinst;
}
// 一般单例不用释放。
// 特殊场景:1、中途需要显示释放 2、程序结束时,需要做一些特殊动作(如持久化)
static void DelInstance()
{
if (_psinst)
{
delete _psinst;
_psinst = nullptr;
}
}
void Add(const pair<string, string>& kv)
{
_dict[kv.first] = kv.second;
}
void Print()
{
for (auto& e : _dict)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
}
class GC
{
public:
~GC()
{
lazy::Singleton::DelInstance();
}
};
private:
// 1、构造函数私有
Singleton()
{
// ...
}
~Singleton()
{
cout << "~Singleton()" << endl;
// map数据写到文件中
FILE* fin = fopen("map.txt", "w");
for (auto& e : _dict)
{
fputs(e.first.c_str(), fin);
fputs(":", fin);
fputs(e.second.c_str(), fin);
fputs("\n", fin);
}
}
// 3、防拷贝
Singleton(const Singleton& s) = delete;
Singleton& operator=(const Singleton& s) = delete;
map<string, string> _dict;
// ...
static Singleton* _psinst;
static GC _gc;
};
Singleton* Singleton::_psinst = nullptr;
Singleton::GC Singleton::_gc;
}