特殊类的设计
- 前言
- 正式开始
- 设计一个类,不能被拷贝
- 设计一个类,只能在堆上创建对象
- 设计一个类,只能在栈上创建对象
- 设计一个类,不能被继承
- 设计一个类,只能创建一个对象(单例模式)
- 饿汉模式
- 懒汉模式
- 总结
前言
点进来的同学可能不知道本篇讲的是啥,先提前看看:
- 请设计一个类,不能被拷贝
- 请设计一个类,只能在堆上创建对象
- 请设计一个类,只能在栈上创建对象
- 请设计一个类,不能被继承
- 请设计一个类,只能创建一个对象(单例模式)
这下子就知道了吧,不过看本篇之前先想想:上面的5个类你都会搞不?
正式开始
就按照上面的内容挨个讲。
一般创建对象就下面三种:
ClassName cn1; // 栈
static ClassName cn2; // 静态区
ClassName* cn3 = new ClassName; // 堆
设计一个类,不能被拷贝
这个很简单,我上篇的博客中也有。
C++98:
让拷贝构造和拷贝赋值只声明不实现,并设置为私有。
只声明的话,链接会报错。
私有是为了防止有人直接在类外实现。
C++11:
让拷贝构造和拷贝赋值后面跟上 = delete。
对这个关键字不熟悉的同学点传送门:【C++】C++11中比较重要的内容介绍。其中就有delete关键字的介绍。
设计一个类,只能在堆上创建对象
三种方法。
法一:析构设置为私有
对象生命周期结束后会自动调用析构。但是这里把析构私有了就不行了。
堆上new的话,可以创建,但是这里有一个问题,就是内存泄漏了,因为没有delete hp,就没有调用对应的析构,这样的话如果类中有成员是在堆上的,就会导致内存泄漏。解决办法就是再改一个共有的函数用来实现析构功能:
这样就不会导致内存泄漏了:
法二:构造设置为私有
这个方法也是需要搞一个公有的接口来专门返回一个堆上开辟的空间:
但是要搞成static的,不然没法创建对象,就不能调用成员函数:
但是同时需要把拷构禁掉,不然还能这样用:
这样生成的copy是在栈上的。
所以要禁掉拷构:
这样就好了。
delete析构
这个方法已经在刚刚的传送门那篇里讲过了,这里就不再说了,直接点传送门:【C++】C++11中比较重要的内容介绍。
设计一个类,只能在栈上创建对象
这个要将构造函数设置为私有,然后再搞一个返回对象的接口:
上面注释的方式也可以。
也是要搞成stack的,不然也是调不了:
而且这里不能将拷构delete掉,因为Create的返回值为传值返回对象,delete掉的话就会导致没法返回了。
但是这样的话就出问题了,static和堆都可以创建对象了:
我们可以重载一下new,直接搞成delete的,这样new就不能用了:
看:
但是这里没办法不让static创建对象,算是一个小缺陷,但是平时一般也不会搞一个static的对象。
设计一个类,不能被继承
C++98:
构造函数私有,这样子类创建对象的时候,调用子类的构造函数会先调用父类的构造函数,父类的构造函数调用不了子类就没法创建对象,没法创建对象的类也就没啥意义了。
C++11:
在父类后面加上final关键字。
这个在我前面继承的博客中有,详细的就不讲了,传送门:【C++】继承知识点详解。
不懂得同学点传送门去看看。
设计一个类,只能创建一个对象(单例模式)
上面的四个类,现实中没有太大的意义,只是为了考一下各位的思维和对基础知识的掌握程度。
但是这个类就很有用了。
单例模式,就是只能创建唯一实例对象。也就是说这个类只能创建出一个对象。
分两种模式,一个叫饿汉模式,一个叫懒汉模式。分开讲。
饿汉模式
意思就是main函数执行之前就创建对象。
怎么搞呢?
首先就是构造函数私有化,不然能一直创建对象。
然后再类内直接定义类对象。而且必须是static的。看:
或者是指针:
_inst / _pinst 是类的成员,可以调用私有的构造函数,但是static必须要在类外初始化。
下面的就不用_inst了,直接用_pinst。
搞一个得到_pinst的接口:
内存池就要用到这里的单例模式,假如说内存池要搞空间的话,给一个接口:
再来个释放空间的:
等等功能,就不写了,这里主要见一下猪跑,知道饿汉模式是啥就行了。
再看一下用法:
不细讲了。
说一下饿汉模式的优缺点。
优点
简单,没有线程安全问题(前面的博客中没有将线程,之后我写了线程的博客之后再说)。
缺点:
- 一个程序中,多个单例,并且有先后创建初始化顺序要求时,饿汉无法控制。
比如程序两个单例类A 和 B,假设要求A先创建初始化,B再创建初始化。- 饿汉单例类,初始化时任务多,会影响程序启动速度。
懒汉模式
懒汉模式是适用对象的时候再创建实例对象。
除了初始化,其他的基本差不多。
我就直接以内存池命名了:
还可以搞的看起来高大上一点:
这就是懒汉模式。其优点就是饿汉的缺点,缺点就是饿汉的优点。
优点:
1、控制顺序。
2、不影响启动速度。
缺点:
1、相对复杂。(线程安全问题没讲)
2、线程安全问题要处理好
总结
说一下饿汉和懒汉在现实中的例子:
想想一下各位小时候写暑假作业是啥样的。放假之前学校已把暑假作业发下去了。肯定有同学趁老师没有收答案前就抓紧时间对着后面的答案一节课干一本,这就是饿汉模式,就是暑假正式开始之前就把作业啃完了。啃完了之后暑假就往死里玩了,啥也不用管。
当然肯定有同学一点都不想写,然后暑假一直在玩,直到最后两三天了,就整天抱着别人写好的作业抄,抄一本是一本,从早上八点干到晚上十点,甚至有时候作业多了还通宵接着干。这就是懒汉模式,等到暑假结束得交作业了才写。
单例对象释放问题:
- 一般情况下,单例对象不需要释放的。因为一般整个程序运行期间都可能会用它。
单例对象在进程正常结束后,也会资源释放。 - 有些特殊场景需要释放,比如单例对象析构时,要进行一些持久化(往文件、数据库写)操作。
到此结束。。。