特殊类的设计

不能背拷贝的类

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

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()实现资源的释放和持久化处理

相关推荐
商吉婆尼2 小时前
天地图API调用注意事项
java·spring·天地图
芒果披萨2 小时前
sql存储过程
java·开发语言·数据库
楚Y6同学2 小时前
QT C++ 实现图像查看器
开发语言·c++·qt·图像查看
yaoxin5211232 小时前
368. Java IO API - 基本文件属性
java·开发语言·python
_日拱一卒2 小时前
LeetCode:最小覆盖字串
java·数据结构·算法·leetcode·职场和发展
禾小西2 小时前
性能测试后的瓶颈定位与调优:自下而上找问题,自上而下解难题
java·测试工具
建军啊2 小时前
java审计进阶
java·开发语言·python
2401_889626922 小时前
Java流程控制与方法全解析
java·开发语言
花千树-0102 小时前
5分钟用 Java 构建你的第一个 AI 应用
java·人工智能·spring boot·langchain·aigc·ai编程