特殊类的设计

不能背拷贝的类

不能调用拷贝构造和赋值运算符重载

c++98实现方式:

cpp 复制代码
class myClass {
public:
	myClass() {
		//
	}
private:
	myClass(const myClass&);
	myClass& operator=(const myClass&);
};

定义为私有是为了在外面不能被调用,只声明不是实现是为了内部不会调用,友元类不能调用,书写反而简单

补充:如果函数只是声明或者在函数内部没有使用形参,可以不写形参名

c++11实现方式:

cpp 复制代码
class myClass {
public:
	myClass() {
		//
	}
	myClass(const myClass&)=delete;
	myClass& operator=(const myClass&)=delete;
private:
};

默认成员函数=delete;表示直接删除这个默认成员函数

只能在堆上创建对象的类

只能通过new,malloc等申请的对象

实现方式:

1.私有构造函数,防止外部通过构造函数创建对象,删除拷贝构造和赋值运算符重载

2.提供一个静态函数,在函数内部实现从堆上创建对象

cpp 复制代码
class myClass {
public:
	static myClass* createObject() {
		return new myClass;
	}
	myClass(const myClass&)=delete;
	myClass& operator=(const myClass&)=delete;
private:
	myClass() {
		//
	}
};

只能在栈上创建对象的类

不能通过new,malloc等申请资源

实现方式:

1.私有构造函数,提供一个静态函数,创建对象并返回

2.内部重载new 并删除

cpp 复制代码
class myClass {
public:
	static myClass createObject() {
		return myClass();
	}
	void* operator new(size_t size) = delete;
private:
	myClass() {
		//
	}
};

补充:当new一个对象时,是不是先看类域中有没有重载new,如果没有,从全局中寻找new

设计一个类不能被继承

c++98方式:

cpp 复制代码
class myClass {
public:
	static myClass createObject() {
		return myClass();
	}
private:
	myClass() {
		//
	}
};

如果有个派生类继承myClass,当创建对象时,需要调用基类的构造函数,但myClass将构造函数私有化,在派生类中不可见,无法调用,所有无法构造对象

c++11方式:

cpp 复制代码
class myClass final{
public:
	
private:
	
};

使用final关键字,表示该类不能被继承

单例设计模式

设计模式:

设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化

单例模式

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

饿汉模式

不管用不用,程序启动就创建

cpp 复制代码
	//饿汉模式
	class Singleton {
	public:
		//第二步,提供一个静态的方法,提供单例对象
		static Singleton& getInstance() {
			return _sinl;
		}

		void push(int t) {
			_lt.push_back(t);
		}
	private:
		//第一步私有构造函数
		Singleton() {
			//
		}

		//第三步,删除拷贝构造和运算符重载
		Singleton(const Singleton&) = delete;
		Singleton& operator=(const Singleton&) = delete;
		//声明
		static Singleton _sinl;

		list<int> _lt;
	};

	//定义,会调用构造函数
	Singleton Singleton::_sinl;	

代码解释:私有构造函数,是防止外部直接调用对象,创建静态的方法提供获取对象的接口,该对象相同且唯一,同时删除拷贝构造和赋值运算符重载,是为了防止拷贝构造方式创建对象。为了对象唯一,将其声明为静态,同时在类外名定义(调用构造函数,应为声明在类里面,可以调用类里面的构造函数)

饿汉模式的缺点:

1.如果单例对象初始化内容很多,影响启动速度

2.如果两个单例类相互有依赖关系

如A,B两个单例类,要求A先创建,B再创建,B的初始化创建依赖A。

懒汉模式

只有在第一次使用时,才创建实例对象,不用就不创建

cpp 复制代码
namespace lazy {
	//懒汉模式
	class Singleton {
	public:
		//第二步,提供一个静态的方法,提供单例对象
		static Singleton& getInstance() {
			if (_sinl == nullptr) {
				_sinl = new Singleton;
			}
			return *_sinl;
		}

		//一般单例用释放,等到进程结束后,资源自动释放
		//特殊情况:1.中途释放资源,2.需要做一些持续化操作
		static void DelInstance() {
			if (_sinl) {
				delete _sinl;
				_sinl = nullptr;
			}
		}
		void push(string t) {
			_lt.push_back(t);
		}
	private:
		//第一步私有构造函数
		Singleton() {
			//
		}

		~Singleton() {
			//
			//比如讲lt里面的资源写到文件里面
			FILE* fin = fopen("lt.txt", "w");
			for (auto& e : _lt) {
				fputs(e.c_str(), fin);
				fputs("\n", fin);
			}			
		}

		//第三步,删除拷贝构造和运算符重载
		Singleton(const Singleton&) = delete;
		Singleton& operator=(const Singleton&) = delete;
		//声明
		static Singleton* _sinl;

		list<string> _lt;
	};
	Singleton* Singleton::_sinl = nullptr;
}

代码解释:一般来说单例对象不需要释放,因为单例对象整个程序只有之一,随着进程接收,资源释放。但是有写特殊场景1.中途释放资源,2.需要做一些持续化操作。这个时候就需要我们写一个释放资源的静态方法,之所以不直接delete是因为单例类是对象而非指针,指针只是整个类的静态成员,调用 DelInstance内部delete资源,同时可以在析构函数内完成持久化的效果

问题:如果有多个懒汉模式的单例类都需要做持久化,手动的释放调用函数,会十分的麻烦,有什么自动的方法?

可以借助RAII的思想处理:

cpp 复制代码
namespace lazy {
	//懒汉模式
	class Singleton {
	public:
		//第二步,提供一个静态的方法,提供单例对象
		static Singleton& getInstance() {
			if (_sinl == nullptr) {
				_sinl = new Singleton;
			}
			return *_sinl;
		}

		//一般单例用释放,等到进程结束后,资源自动释放
		//特殊情况:1.中途释放资源,2.需要做一些持续化操作
		static void DelInstance() {
			if (_sinl) {
				delete _sinl;
				_sinl = nullptr;
			}
		}
		void push(string t) {
			_lt.push_back(t);
		}
		class GC {
		public:
			~GC() {
				lazy::Singleton::DelInstance();
			}
		};
	private:
		//第一步私有构造函数
		Singleton() {
			//
		}

		~Singleton() {
			//
			//比如讲lt里面的资源写到文件里面
			FILE* fin = fopen("lt.txt", "w");
			for (auto& e : _lt) {
				fputs(e.c_str(), fin);
				fputs("\n", fin);
			}			
		}

		//第三步,删除拷贝构造和运算符重载
		Singleton(const Singleton&) = delete;
		Singleton& operator=(const Singleton&) = delete;
		//声明
		static Singleton* _sinl;

		static GC _gc;

		list<string> _lt;
	};
	Singleton* Singleton::_sinl = nullptr;
	Singleton::GC Singleton::_gc;
}

我们通过使用一个内部类处理,当进程结束后,GC的静态对象会调用销毁函数,销毁函数内部调用隶属于类的static void DelInstance()实现资源的释放和持久化处理

相关推荐
这是个栗子16 分钟前
前端开发中的常用工具函数(八)
开发语言·前端·javascript
凤凰院凶涛QAQ30 分钟前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
研☆香38 分钟前
为什么变量声明在赋值前也能使用?—— 深入理解 JavaScript 变量提升与作用域
开发语言·前端·javascript
右耳朵猫AI1 小时前
PHP周刊2026W28 | 安全更新、Laravel 13.18、Twig 3.28
开发语言·php·laravel
second601 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
郝学胜-神的一滴1 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
bksczm1 小时前
linux之线程概念和控制
linux·开发语言·c++
掘金_答案1 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
JackieZhengChina2 小时前
零依赖轻量级JS悬浮提示插件title2tip-js的使用教程
开发语言·javascript·ecmascript
hehelm2 小时前
Linux网络编程—TCP字典翻译系统
linux·开发语言·网络·c++·tcp/ip