C++特殊类实现

目录

前言

一、HeapOnly

二、StackOnly

三、NonInherit

四、单例模式

4.1 饿汉模式

4.2 懒汉模式


前言

        对于特殊类的实现,我们首先要会设计一个不能被拷贝的类,其思路就是让类不能调用拷贝构造函数以及赋值运算符操作即可。

        在C++98中,可以只声明不定义构造函数以及赋值运算符操作,并将他们设为私有防止在类外定义它们。

class CopyBan
{
    // ...
    
private:
    CopyBan(const CopyBan&);
    CopyBan& operator=(const CopyBan&);
    //...
};

        在C++11中,扩展了delete写法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。

class CopyBan
{
    // ...
    CopyBan(const CopyBan&)=delete;
    CopyBan& operator=(const CopyBan&)=delete;
    //...
};

一、HeapOnly

设计一个只能在堆上创建对象的类:

方法一、析构函数私有化

        我们可以将析构设为私有,这样就很巧妙的规避了析构函数的调用,new的对象是不会调用析构的,因此为了删除,在类内部添加一个Destroy函数。

方法二、构造函数私有化

        我们将构造函数私有化,然后自己提供一个Create函数用于new一个对象,但是需要在前面加static这样在类外即使最开始没有对象也可以通过调用CreateObj来创造一个对象。同时要把拷贝构造和赋值运算符操作都delete,因为在外部调用它们时创造的对象是在栈上的。

//构造函数私有化
class HeapOnly
{
public:
	static HeapOnly* CreateObj()		//加了satic才能在外部不用声明对象直接创造对象
	{
		return new HeapOnly;
	}
private:
	HeapOnly()
	{
		//...
	}
    HeapOnly(const HeapOnly& hp) = delete;
	HeapOnly& operator = (const HeapOnly& hp) = delete;
};
int main()
{    
	HeapOnly hp1;						        //栈
	static HeapOnly hp2;				        //静态区
	HeapOnly* hp3 = HeapOnly::CreateObj();		//堆
	return 0;
}

二、StackOnly

设计一个只能在栈上创建的类:

        我们对其构造函数私有化并提供自己的创建对象的函数,同时delete new操作符,防止如StackOnly* hp4 = new StackOnly(hp3)情况发生。

class StackOnly
{
public:
	static StackOnly CreateObj()		//加了satic才能在外部不用声明对象直接创造对象
	{
		StackOnly st;
		return st;
	}
private:
	StackOnly()
	{
		//...
	}
	//对一个类实现专属operator new  
	void* operator new(size_t size) = delete;
};

int main()
{
	//StackOnly hp1;
	//static StackOnly hp2;
	//StackOnly* hp3 = new StackOnly;
	StackOnly hp3 = StackOnly::CreateObj();
	StackOnly copy(hp3);
	// StackOnly* hp4 = new StackOnly(hp3);
	return 0;
}

三、NonInherit

设计一个不能被继承的类:

方法一、final修饰

class A final
{
	//...
};

方法二、构造函数私有化

class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit(){}
};

        当把构造函数私有化时,对于派生类是不可见的,而派生类又必须调用父类的构造函数,因此就无法继承了。

四、单例模式

单例模式即设计一个类,只能创建一个对象

4.1 饿汉模式

        就是说不管你将来用不用,程序启动时(main函数之前)就创建一个唯一的实例对象。        

//饿汉模式
namespace hungry
{
	class Singleton
	{
	public:
		//2.提供获取单例对象的接口函数
		static Singleton& GetInstance()
		{
			return _sinst;
		}
	private:
		//1.构造函数私有化
		Singleton()
		{

		}
		map<string, string> _dict;
		static Singleton _sinst;		//类里声明

		// 3、防拷贝
		Singleton(const Singleton& s) = delete;
		Singleton& operator=(const Singleton& s) = delete;

	};
	Singleton Singleton::_sinst;	//类外定义
}

缺点:

  1. 如果单例对象初始化内容很多,就会影响启动速度
  2. 如果两个单例类互相有依赖关系,这个模式是不能保证初始化的先后顺序的

4.2 懒汉模式

//懒汉模式
namespace lazy
{
	class Singleton
	{
	public:
		// 2、提供获取单例对象的接口函数
		static Singleton& GetInstance()
		{
			if (_psinst == nullptr)
			{
				// 第一次调用GetInstance的时候创建单例对象
				_psinst = new Singleton;
			}

			return *_psinst;
		}

		// 一般单例不用释放。
		// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)
		static void DelInstance()
		{
			if (_psinst)
			{
				delete _psinst;
				_psinst = nullptr;
			}
		}

		void Add(const pair<string, string>& kv)
		{
			_dict[kv.first] = kv.second;
		}

		void Print()
		{
			for (auto& e : _dict)
			{
				cout << e.first << ":" << e.second << endl;
			}
			cout << endl;
		}

		class GC
		{
		public:
			~GC()
			{
				lazy::Singleton::DelInstance();
			}
		};

	private:
		// 1、构造函数私有
		Singleton()
		{
			// ...
		}

		~Singleton()
		{
			cout << "~Singleton()" << endl;

			// map数据写到文件中
			FILE* fin = fopen("map.txt", "w");
			for (auto& e : _dict)
			{
				fputs(e.first.c_str(), fin);
				fputs(":", fin);
				fputs(e.second.c_str(), fin);
				fputs("\n", fin);
			}
		}

		// 3、防拷贝
		Singleton(const Singleton& s) = delete;
		Singleton& operator=(const Singleton& s) = delete;

		map<string, string> _dict;
		// ...

		static Singleton* _psinst;
		static GC _gc;
	};

	Singleton* Singleton::_psinst = nullptr;
}

优点:

  1. 延迟加载:懒汉模式实现了延迟加载,即在需要使用实例时才进行创建。这样可以节省系统资源,提高程序的性能和效率。
  2. 节省内存:由于懒汉模式在首次使用时创建实例,因此避免了在程序启动时就创建实例并占用内存的情况。这对于一些资源消耗较大的对象来说尤为重要。

缺点:

  1. 线程安全性:懒汉模式在多线程环境下可能存在线程安全问题。如果多个线程同时调用获取实例的方法,可能会导致创建多个实例,违反了单例模式的原则。
  2. 需要加锁:为了解决线程安全问题,懒汉模式需要在获取实例的方法中进行加锁操作。这会引入额外的开销,并可能导致性能下降。
  3. 非线程安全的优化:为了避免每次获取实例都进行加锁操作,可以对懒汉模式进行线程安全的优化,例如使用双重检查锁定(Double-Checked Lock
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值