【C++】特殊类的设计

目录

类的对象只能在堆上创建

类的对象只能在栈上创建

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

饿汉

懒汉


本篇博客就是说给一个需求,然后根据需求和类的一些语法规则设计出符合要求的类,比如说我们之前的不能拷贝的类:C++98的做法就是将拷贝构造仅声明且声明在私有,这样编译器不仅不会自动生成,外部也无法调用私有;C++11有关键字delete就可以直接解决,我们再来看一些其他的需求

类的对象只能在堆上创建

对于这种需求我们一般的思路就是封死掉大方向,然后给要求的方向开小门。就是说,我们把构造禁掉,然后单创建一个函数用来专门去堆上开辟空间,这个函数如果是普通成员函数,需要对象来调用,所以我们设置成静态成员函数。至于说拷贝构造和赋值运算符重载都要禁掉,我们就可以这么写

class HeapOnly
{
public:
	template<class...Args>
	static HeapOnly* Creatobj(Args&&...args)
	{
		HeapOnly* tmp = new HeapOnly(forward<Args>(args)...);
		return tmp;
	}
	/*static HeapOnly* Creatobj(int a = 0, const char* str= "aaaaa", vector<double>&& vd = vector<double>())
	{
		HeapOnly* tmp = new HeapOnly(a,str,move(vd));
		return tmp;
	}*/
	HeapOnly(const HeapOnly& ho) = delete;//HeapOnly ho1(*pho1);
	HeapOnly& operator=(const HeapOnly& ho) = delete;//*pho1 = *pho2;
	void Destroyobj()
	{
		delete this;
		cout << "delete:" << this << endl;
	}
private:
	HeapOnly(int a = 0, const char* str = "aaaaa", vector<double>&& vd = vector<double>())
		:_a(a)
		,_str(str)
		,_vd(vd){}

	int _a;
	string _str;
	vector<double> _vd;
};

或者是我们把析构函数私有化,这样因为调不了析构,所以对象就无法在栈上生成,所以我们就可以去堆上申请(堆上申请的不会自动调用析构),然后创建destroy函数销毁对象

class HeapOnly
{
public:
	HeapOnly(int a = 0, const char* str = "aaaaa", vector<double>&& vd = vector<double>())
		:_a(a)
		, _str(str)
		, _vd(vd) {}


	void Destroyobj()
	{
		delete this;
		cout << "delete:" << this << endl;
	}
private:
	~HeapOnly()
	{
		cout << "~HeapOnly()" << endl;
	}
	int _a;
	string _str;
	vector<double> _vd;
};

我们可以这样使用

类的对象只能在栈上创建

这个和只能在堆上创建的大思路是一样的,我们构造私有化,然后单创建一个函数,这个函数就用来返回在栈上的对象,但是返回对象要用到拷贝构造,所以拷贝构造不能禁用。拷贝构造不禁用就可以new对象了,但是new会去调用operator new和(拷贝)构造,所以把operator new给封掉

class StackOnly
{
public:
	template<class...Args>
	static StackOnly Creatobj(Args&&...args)
	{
		return StackOnly(forward<Args>(args)...);
	}

	StackOnly(const StackOnly&so)
		:_a(so._a)
		,_str(so._str){}
	void* operator new(size_t n) = delete;

private:
	StackOnly(int a = 0, const char* str = "aaaa")
		:_a(a)
		,_str(str){}

	int _a;
	string _str;
};

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

有的类就要求只创建一个对象,比如内存池,我们每次申请内存都去同一个内存池;比如用来存配置信息的类,我们希望配置信息只有一份,那么这种类的设计方式有饿汉和懒汉两种方式,饿汉就是说在main函数之前这个对象就创建出来了,懒汉就是说等用到的时候才创建,我们下面就来介绍一下这两种方式

饿汉

因为只能创建一个对象,所以要将构造私有化,并且这个对象要创建成静态的,我们再创建一个函数,随时返回这个对象的指针,这样就可以保证要求了

namespace hunger
{
	class Singleton
	{
	public:
		static Singleton* Getobj()
		{
			return &sin;
		}
		void print()
		{
			cout << _a << endl;
			for (auto& e : _vs)
				cout << e << ' ';
			cout << endl;
		}
		Singleton(const Singleton&) = delete;
	private:
		Singleton(int a = 0, vector<string>&& vs = {"aaaaaa","bbbbb"})
			:_a(a)
			,_vs(vs){}

		int _a;
		vector<string> _vs;

		static Singleton sin;
	};
	Singleton Singleton::sin(111, { "abc","def" });

};

这种创建方式也是有一些问题,如果单例对象数据较多,那么构造初始化这些对象的成本较高,影响程序的启动速度,迟迟进入不了main函数

如果两个单例分别位于两个文件中,它们两个需要有初始化的先后顺序,但是饿汉就无法控制先后顺序,因为很难说哪个文件先,哪个文件后

懒汉

就是说第一次使用的时候再去创建对象,我们也是创建一个静态成员对象,只不过这次是指针,因为通过判断指针是否为空就可以判断是否已经创建了对象

namespace lazy
{
	class Singleton
	{
	public:
		static Singleton* Getpobj()
		{
			if (psin == nullptr)
			{
				psin = new Singleton;
			}
			return psin;
		}
		static void destroyobj()
		{
			delete psin;
		}
		//内部类
		class GC
		{
		public:
			~GC()
			{
				Singleton::destroyobj();
			}
		};
		static GC gc;

	private:
		Singleton(int a = 0, vector<string>&& vs = { "aaaaaa","bbbbb" })
			:_a(a)
			, _vs(vs) {}

		int _a;
		vector<string> _vs;

		static Singleton* psin;
	};
	Singleton* Singleton::psin = nullptr;
	Singleton::GC Singleton::gc;
};

其实还有一种特别简单的方式,就是创建局部的静态对象,那么第一次调用函数就会初始化,后面都不会执行这句代码了

	class Singleton
	{
	public:
		static Singleton* Getpobj()
		{
			static Singleton psin;
			return &psin;
		}
		
		private:
		Singleton(int a = 0, vector<string>&& vs = { "aaaaaa","bbbbb" })
			:_a(a)
			, _vs(vs) {}

		int _a;
		vector<string> _vs;
	};

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值