在程序中可能有多个单例,有没有什么方法可以只实现一次单例而能够复用其代码从而实现多个单例呢? 答案是肯定的,代码复用技术有两种典型方法:
- 模板技
- 继承
■ 单例类的模板
● 奇异递归模板模式(CRTP ,Curiously recurring template pattern)
代码示例如下:
#include <iostream>
using namespace std;
template<typename T>class MySingleton
{
public:
static T& getInstance()
{
static T instance;
return instance;
}
virtual ~MySingleton()
{
cout << "This is destructor!" << endl;
}
MySingleton(const MySingleton&) = delete;
MySingleton& operator=(const MySingleton&) = delete;
protected:
MySingleton()
{
cout << "This is constructor!" << endl;
}
};
class DerivedSingleton : public MySingleton<DerivedSingleton>
{
friend class MySingleton<DerivedSingleton>;
public:
DerivedSingleton(const DerivedSingleton&) = delete;
DerivedSingleton& operator=(const DerivedSingleton&) = delete;
private:
DerivedSingleton() = default;
};
int main()
{
DerivedSingleton& instance1 = DerivedSingleton::getInstance();
DerivedSingleton& instance2 = DerivedSingleton::getInstance();
return 0;
}
以上实现单例的模板基类,使用方法如例所示,子类需要将自己作为模板参数 T 传递给 MySingleton< T >模板; 同时需要将基类声明为友元,这样才能调用子类的私有构造函数。
■ 基类模板要点:
- 构造函数必须是 protected才能继承;
- 使用了CRTP(奇异递归模板模式)
- 在这里基类的析构函数可以不需要 virtual ,因为子类在应用中只会用 DerivedSingleton类型,保证析构时和构造时的类型一致
● 不需要在子类声明友元的实现(使用代理类令牌token)
核心在于使用一个代理类令牌 token,子类构造函数需要传递token才能构造,但是把 token保护其起来, 然后子类的构造函数就可以是公有的了,这个子类只有 DerivedSingleton(token)这样的构造函数,用户便无法自己定义一个类的实例了,起到控制其唯一性的作用。代码如下:
#include <iostream>
using namespace std;
template<typename T>class MySingleton
{
public:
static T& getInstance() noexcept(is_nothrow_constructible<T>::value)
{
static T instance{token()};
return instance;
}
virtual ~MySingleton() = default;
MySingleton(const MySingleton&) = delete;
MySingleton& operator=(const MySingleton&) = delete;
protected:
struct token{}; // helper class
MySingleton() noexcept = default;
};
class DerivedSingleton: public MySingleton<DerivedSingleton>
{
public:
DerivedSingleton(token)
{
cout << "This is constructor!" << endl;
}
~DerivedSingleton()
{
cout << "This is destructor!" << endl;
}
DerivedSingleton(const DerivedSingleton&) = delete;
DerivedSingleton& operator=(const DerivedSingleton&) = delete;
};
int main()
{
DerivedSingleton& instance_1 = DerivedSingleton::getInstance();
DerivedSingleton& instance_2 = DerivedSingleton::getInstance();
return 0;
}
更多设计模式,请关注: