首言
在以前的文章中,我写了一种单例模式。不过那种写法会比较麻烦,要加好几行代码。如今看到了大佬写的新的单例模式,我进行了改进,比较好玩,现在记录下来。
大佬的单例模式
cpp
#include <stdexcept>
template <typename T>
class Singleton {
public:
template<typename... Args>
static T* Instance( Args&&... args ) {
if ( m_pInstance == nullptr )
m_pInstance = new T( std::forward<Args>( args )... );
return m_pInstance;
}
static T* GetInstance( ) {
if ( m_pInstance == nullptr )
throw std::logic_error( "the instance is not init, please initialize the instance first" );
return m_pInstance;
}
static void DestroyInstance( ) {
delete m_pInstance;
m_pInstance = nullptr;
}
private:
static T* m_pInstance;
};
template <class T> T* Singleton<T>::m_pInstance = nullptr;
cpp
#include "Singleton.h"
class Test: public Singleton<Test>
{
public:
Test(int selfNum):_selfNum(selfNum) {};
void sayhello(){
std::cout<<"hello--"<<_selfNum<<std::endl;
};
protected:
int _selfNum = -1;
};
使用时是这样的
cpp
Test one(1);
Test two(2);
one.sayhello();
two.sayhello();
Singleton<Test>::Instance(3);
Singleton<Test>::GetInstance()->sayhello();
Test::Instance(4);
Test::GetInstance()->sayhello();
打印结果
cpp
hello--1
hello--2
hello--3
hello--3
为什么最后两条是一样的数字呢?因为 Test 继承了 Singleton<Test> ,所以最后两种写法是等价的。
这里有一个大问题,假如别人使用这个类,同时忘记需要写成单例模式,就像 Test one(1);一样,那么代码就乱套了,针对这个问题,进行下列改动。
改进后代码
cpp
#include "Singleton.h"
class Test: public Singleton<Test>
{
public:
friend class Singleton;
void sayhello(){
std::cout<<"hello--"<<_selfNum<<std::endl;
};
protected:
Test(int selfNum):_selfNum(selfNum) {};
int _selfNum = -1;
};
使用了 friend 关键字,让 Singleton 可以访问 Test 的被保护函数,同时将 Test 的构造函数放入保护段,这样封住了可能出问题的部分。