栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++易错知识点笔记(九)学了静态成员函数,现在尝试写一个单例模式

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++易错知识点笔记(九)学了静态成员函数,现在尝试写一个单例模式

单例模式是指一个类只能创建一个类对象,本文从第一种单例模式的写法开始介绍,后一种单例模式均是对前一种单例模式可能出现的问题的改进,写法大同小异,读者可跟随文章一起分析。

第一种单例模式
#include
using namespace std;
class Clog {
private:
	static Clog* ptr;
	Clog() = default;
public:
	//唯一的创建类的接口
	static Clog* createObject(){
		if(ptr==nullptr)
		    ptr=new Clog();
		return ptr;
	}
};
Clog* Clog::ptr = nullptr;


int main()
{
	Clog* p = Clog::createObject();
	Clog* p1 = Clog::createObject();

	delete p;
	delete p1;
	//指针接收创建这个唯一的类就是需要手动释放资源,容易引起线程安全问题
}

分析
1)将构造函数声明为私有,而暴露一个createObject()函数创造类对象。
2)将createObject()类对象声明为static,方便我们直接用类名调用该函数,而不必陷入“调用函数应该先创建对象,而创建对象需要调用该函数的这种鸡生蛋,蛋生鸡” 问题。
3)现在需要一个Clog类的指针作为createObject()函数的返回值,而只有静态成员变量才能不用对象就可以调用,而且静态函数内部只能用静态成员变量,所以在类中声明一个静态的Clog指针。
4)在main函数中直接调用Clog类中的createObject方法,会返回一个Clog类对象的指针=Clog::ptr,是Clog类中的静态成员变量,所以不论在main函数中调用多少次,返回的都是唯一的那一个Clog类中的静态成员变量ptr的值。
5)从此我们想要在程序的任何地方使用该单例对象都可以直接调用Clog类中的createObject方法返回这个对象供我们操作。也就是说实现了单例模式,单例模式有什么用呢?比如说我们编程序的时候想要记录我们的日志,那么就可以用这个唯一的单例模式的类对象进行记录。
该方法的不足之处
createObject()函数返回的是Clog*类型new出来的堆对象,我们需要注意内存释放的问题。容易引起线程安全性问题。
----->解决方法:createObject()函数返回Clog 类型对象栈对象,并用static关键字声明该对象,让该对象的声明周期在整个程序运行期间。(这里不理解可以看看static关键字用法)见第二种单例模式。

第二种单例模式
//#include
using namespace std;
class Clog {
private:
	Clog() = default;

public:
	//唯一的创建类的接口
	static Clog* createObject() {
		static Clog p;
		return &p;
	}
	
};
int main()
{

	Clog* p = Clog::createObject();
	Clog* p1 = Clog::createObject();

}

该方法已经解决了内存释放的问题,但是我们还是可以注意到,他返回的是一个类的指针,既然是指针,难免有同学会一不小心去delete他,运行的时候引起错误。
解决方法------->不去返回一个类的指针了,返回一个类的引用。见第三种单例模式。

第三种单例模式
#include
using namespace std;
class Clog {
private:
	Clog() = default;
	
public:
	//唯一的创建类的接口
	static Clog& createObject() {
		static Clog p;
		return p;
	}
};


int main()
{ 
	Clog& p = Clog::createObject();
	Clog& p1 = Clog::createObject();
}

现在问题已经解决,但是我们又想到,有些同学在main函数中调用这个createObject接口可能会忘了用Clog类型的引用去接,而是用Clog类型的对象去接,例如Clog p2 = Clog::createObject();,这里的p2对象接的就不是我们想要的单例模式的唯一的对象了,而是因为一个“=”号调用了Clog类中的拷贝构造函数,拷贝构造了一个对象,最终的结果就是又生成了一个新对象。

---->解决方法:禁用拷贝构造函数或者禁用”=“运算符重载。见第四种单例模式。

第四种单例模式
#include
using namespace std;
class Clog {
private:
	Clog() = default;
	
public:
	//唯一的创建类的接口
	static Clog& createObject() {
		static Clog p;
		return p;
	}
	Clog(Clog& obj) = delete;
	Clog* operator= (Clog& obj) = delete;//禁用其中任何一个函数或者都禁用
};


int main()
{ 
	Clog& p = Clog::createObject();
	Clog& p1 = Clog::createObject();
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/702622.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号