36 特殊类设计

发布于:2024-07-11 ⋅ 阅读:(16) ⋅ 点赞:(0)

类,不能被拷贝

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝。

  • c++98
    将拷贝构造函数与赋值云悬浮重载只声明不定义,并且将其访问权限设置为私有
class CopyBan
 {
 // ...
 private:
 CopyBan(const CopyBan&);
 CopyBan& operator=(const CopyBan&);
 //...
 };

原因:
1.设置为私有:如果只声明没有设置成private,用户自己如果在类外定义了,就不能禁止拷贝了
2.只声明不定义:不定义是y8inwei该函数根本不会调用,定义了也没有意义,不写反而更简单,如果定义了就不会防止成员函数内部拷贝了

  • c++11
    c++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上delete,表示让编译器删掉该默认成员函数
class CopyBan
 {
 // ...
 CopyBan(const CopyBan&)=delete;
 CopyBan& operator=(const CopyBan&)=delete;
 //...
 };

类,只能在堆上创建对象

实现方式:
1.将类的构造函数私有,拷贝构造函数私有。防止别人调用拷贝在栈上生成对象
2.提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
一种是析构私有,提供函数析构,一种是构造私有,提供函数返回创建对象

class HeapOnly    
{     
public:     
static HeapOnly* CreateObject()  
    {      
return new HeapOnly;    
    }
 private:    
HeapOnly() {}
 // C++98
 // 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要
// 2.声明成私有
HeapOnly(const HeapOnly&)// or
 // C++11    
HeapOnly(const HeapOnly&) = delete;
 };

类,只能在栈上创建对象

将构造函数私有化,设计静态方法返回,同时防止拷贝构造,返回对象需要用拷贝,将new重载禁掉

class StackOnly
 {
 public:
 static StackOnly CreateObj()
 {
 return StackOnly();
 }
 // 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉
// StackOnly obj = StackOnly::CreateObj();
 // StackOnly* ptr3 = new StackOnly(obj);
 void* operator new(size_t size) = delete;
 void operator delete(void* p) = delete;
 private:
 StackOnly()  
:_a(0)
 {}
 private:
 int _a;
 }

类,不能被继承

c++98方式

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
 {
 public:
 static NonInherit GetInstance()
 {
 return NonInherit();
 }
 private:
 NonInherit()
 {}
 };

c++11方法:
关键字final,类不能被继承

class A  final
 {
 // ....
 };

类,只能创建一个对象(单例模式)

设计模式(Desgin Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西?就像人类历史经过一次次打仗总结的套路,研究了《孙子兵法》

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编写工程化,是软件工程的基本脉络

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

单例模式有两种实现模式:

  • 饿汉模式
    在程序启动的时候就创建唯一的实例对象,不管用不用
class Singleton
{
public:
	static Singleton* GetInstance()
	{
		return &_instance;
	}

private:
	//防拷贝
	Singleton() {};
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;
	static Singleton _instance;
};

//入口前初始化
Singleton Singleton::_instance;

优点:简单
缺点:导致进程启动慢,如果由多个单例类对象实例启动顺序不确定

如果单例对象再多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好

  • 懒汉模式
    如果单例对象构造十分耗时或者占用很多资源,比如加载插件,初始化网络连接读取文件等,有可能对象程序运行时不会用到,那么也要在程序一开始就初始化,会导致启动时很慢,这种情况使用懒汉模式(延迟加载)更好

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		if (_instace == nullptr)
		{
			_instace = new Singleton();
		}
		
		return _instace;
	}

	//资源回收
	class CGarbo
	{
	public:
		CGarbo()
		{
			if (_instace)
			{
				delete _instace;
			}
		}
	};

private:

	Singleton() {};
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;

	static Singleton* _instace;
	static CGarbo _garbo;
};

Singleton* Singleton::_instace = nullptr;
Singleton::CGarbo _garbo;  //程序结束自动调用析构释放单例对象

//获取对象
Singleton::GetInstance();