文章目录
不能被拷贝的类
设计一个不能被拷贝的类,通常来说方法就是把拷贝构造和赋值重载都设置为私有,这样就不能进行拷贝了
cpp
class A
{
public:
A()
{}
private:
A(const A& a);
A& operator=(const A& a);
};
对于C++11来说,新增了delete的用法,可以直接删除这个函数,也能做到相同的效果
cpp
class A
{
public:
A()
{}
A(const A& a) = delete;
A& operator=(const A& a) = delete;
private:
};
设计一个只能在堆上创建对象的类
这是一个比较奇怪的要求,但是也有对应实现的方法:
- 把类的构造函数设置为私有
- 提供一个静态的成员函数,通过函数调用来进行堆上对象的创建
cpp
// 将构造函数都设置为私有
class A
{
private:
A();
A(const A&);
A& operator=(const A&);
};
int main()
{
A* pa = new A;
A a;
}
这样就可以保证无法创建出对象,但是同样的也无法直接new出一个对象,因为new操作符底层是调用了operator new和构造函数
解决的方法是,设置一个静态的成员函数,用来完成堆上对象的创建
cpp
class A
{
public:
static A* create()
{
A* pa = new A;
return pa;
}
private:
A();
A(const A&);
A& operator=(const A&);
};
int main()
{
A* pa = A::create();
return 0;
}
到这里正好进行回顾一下static修饰成员函数表示的意义:
- static修饰成员函数,代表的是这个成员函数在类作用域内是全局函数,但是不能调用非静态成员变量和成员函数
- static修饰成员函数,该成员函数没有this指针
所以基于这样的原因,就可以设计出上面的特殊类,把构造函数都私有化,但是保留一个静态成员函数,这样就可以通过类的作用域来调用new一个对象出来,但不能在栈上开辟空间
设计一个类,只能在栈上创建对象
这个实现的逻辑其实和前面基本相同,但是唯一的区别是要防止通过new操作符,因此可以这样设计
cpp
class A
{
public:
static A create()
{
return A();
}
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
private:
A()
{}
};
int main()
{
A a = A::create();
A* pa = new A(a);
return 0;
}
单例模式:设计一个只能创建一个对象的类
什么是单例模式?
单例模式指的是,一个类只能创建一个对象,保证系统中只存在这样一个实例,提供访问它的全局访问点,这个实例被所有的程序模块所共享
使用场景?
简单来说,单例模式的使用场景之一就是对于一些特殊的情况,例如对于内存池来说,如果使用的不是单例模式,可能会创建出很多的内存池,那么在进行空间的申请就会有很奇怪的错误出现,不方便管理内存,因此有了单例模式,不管在什么场景下都只能有一个实例,所有的操作都必须在这个实例下进行,就完成了单例模式设计的初衷
如何设计单例模式?
单例模式的设计通常有两种,一种是饿汉模式,一种是懒汉模式,那么下面就基于这两种模式分别进行设计
饿汉模式
不管你将来用不用,程序启动时就创建一个唯一的实例对象'''
如何保证是只有一个?保证的原理基础是用static修饰成员变量,但这个成员变量就是一种类的实例
static修饰成员变量?
static修饰成员变量,表示一种声明,初始化要在类体外进行初始化,简单来说就是只是在类的内部声明了有这样的一个实例,但是并不占用类的内部内容,并且更便携的是,它还属于这个类,就意味着它可以调用类的内部成员函数完成一些内容,并且整个作用域内只有一份
cpp
// 单例
// 饿汉模式:提前(main函数启动时)创建好实例对象
// 优点:实现简单
// 缺点:1、可能会导致进程启动慢、2、如果两个单例有启动先后顺序,那么饿汉无法控制
class A
{
public:
static A* GetInstance()
{
return &_inst;
}
void Add(const string& key, const string& value)
{
_dict[key] = value;
}
void Print()
{
for (auto& kv : _dict)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
private:
A()
{}
A(const A& aa) = delete;
A& operator=(const A& aa) = delete;
map<string, string> _dict;
int _n = 0;
static A _inst;
};
A A::_inst;
从上面的示例代码中其实可以看出这样的原理,将这个成员变量用static在类内修饰,并且把构造函数和拷贝构造等等的函数都放到私有的部分,这样就可以使得在整个类域中只有一个实例,在外部通过构造函数是无法创建出第二个实例,并且还能调用类内的成员函数,因为它本身其实是属于类的一部分
懒汉模式
懒汉模式在饿汉模式的基础上新增了一个指针的实例化过程,就可以保证在需要的时候进行初始化
cpp
// 懒汉模式:第一次用的时候再创建(现吃现做)
// todo:线程安全问题
// new的懒汉对象一般不需要释放,进程正常结束会释放资源
// 如果需要做一些动作,比如持久化,那么可以利用gc类static对象搞定
class B
{
public:
static B* GetInstance()
{
if (_inst == nullptr)
{
_inst = new B;
}
return _inst;
}
void Add(const string& key, const string& value)
{
_dict[key] = value;
}
void Print()
{
for (auto& kv : _dict)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
static void DelInstance()
{
if (_inst)
{
delete _inst;
_inst = nullptr;
}
}
private:
B()
{}
~B()
{
// 持久化:要求把数据写到文件
cout << "数据写到文件" << endl;
}
B(const B& aa) = delete;
B& operator=(const B& aa) = delete;
map<string, string> _dict;
int _n = 0;
static B* _inst;
class gc
{
public:
~gc()
{
DelInstance();
}
};
static gc _gc;
};
B* B::_inst = nullptr;
B::gc B::_gc;