C++ 单例模式 模版类(Meyers‘ Singleton)

自己实现的Meyers’ Singleton的单例模式模板类。

1 不继承

具体类无需继承, 使用Singleton<Test>::getInstance()获得唯一实例。

template<typename T>
class Singleton
{
private:
	Singleton() = default;  // 设置为私有(protected也行),禁止外部直接构造

public:
	Singleton(const Singleton&) = delete; // 禁止拷贝构造
	Singleton& operator = (const Singleton&) = delete; // 禁止拷贝赋值
	~Singleton() = default;

public:
	static T& getInstance() //  Meyers' Singleton 
	{
		static T instance;
		return instance;
	}
};

class Test
{
public:
	Test() = default;
	~Test() = default;

public:
	void Func() { std::cout << "Test::Func()" << std::endl; }
};

#define TestInstance Singleton<Test>::getInstance() // 这里注意没有分号

调用如下:

int main()
{
	TestInstance.Func();
	return 0;
}

这种实现方式简单、方便,无需继承。
由于无需继承,通过Test类声明无法知道该类为单例类,意义不明确。
由于Singleton中需要调用Test的构造函数,所以必须将其声明为public。这会导致无法阻止外部直接构造Test对象。

2 继承

template<typename T>
class Singleton
{
public:
	~Singleton() = default;

	static T& getInstance() //  Meyers' Singleton 
	{ 
		static T instance;
		return instance;
	}

private:
	Singleton(const Singleton&) = delete; // 禁止拷贝构造
	Singleton& operator = (const Singleton&) = delete; // 禁止拷贝赋值

protected: // 允许被继承类调用
	Singleton() = default;  // 设置为私有,禁止外部直接构造
};

class Test : public Singleton<Test>
{
public:
	void Func() { std::cout << "Test::Func()" << std::endl; }

public: // 只能为public,否则编译报错,不能阻止外部调用
	Test() = default;
};

#define TestInstance Test::getInstance()

Test继承Singleton,通过类声明就知道Test是个单例类。但是构造函数依然只能声明为public,导致外部依旧能直接调用构造Test对象。

3 继承+友元

template<typename T>
class Singleton
{
public:
	friend typename T; // 友元声明

public:
	~Singleton() = default;

	static T& getInstance() //  Meyers' Singleton 
	{ 
		static T instance;
		return instance;
	}

private:
	Singleton(const Singleton&) = delete; // 禁止拷贝构造
	Singleton& operator = (const Singleton&) = delete; // 禁止拷贝赋值

private:
	Singleton() = default;  // 设置为私有,禁止外部直接构造
};

class Test : public Singleton<Test>
{
public:
	friend class Singleton<Test>;  // 友元声明

public:
	void Func() { std::cout << "Test::Func()" << std::endl; }

private: // 构造函数可以声明为private,阻止外部直接调用
	Test() = default;
};

#define TestInstance Test::getInstance()

通过相互声明为友元,Test的构造函数即使声明为private,Singleton的依旧能访问其构造函数,不会编译报错。
同时private阻止外部直接构造Test对象,只能通过Test::getInstance()获取唯一实例。当然,这就要求新类继承自Singleton时必须将Singleton声明自己的友元类。

4 继承+友元(小改版)

template<typename T>
class Singleton
{
protected: // 不能直接构造,同时子类可访问,这是protected的优势
	Singleton() = default;

public: // 不提供拷贝构造函数和赋值函数
	Singleton(const Singleton& one) = delete;
	Singleton& operator=(const Singleton& one) = delete;

public: // 全局访问函数
	static T& GetInstance()
	{
		static T instance;
		return instance;
	}
};

class Test : public Singleton<Test> // 继承自Singleton<TestClass>
{
public: // 必须提供
	friend Singleton<Test>;

private: // 不能直接构造,也可使用protected
	Test() = default;

public:
	void TestFunc()
	{
	}
};

当Test继承子Singleton<Test>后,需要改动的地方有两处:

  • 声明Singleton<Test>为友元。
  • 声明构造函数为private或者protected。

感觉还是比较麻烦,想最终实现的功能是:一个类想要变成单例类,只需要继承自单例模板类即可,无需再做其他修改。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值