首页 > 编程语言 >C++单例基类

C++单例基类

时间:2024-03-20 14:45:07浏览次数:35  
标签:std SingletonBase 基类 C++ instance 单例 派生类

要实现一个安全的C++单例基类,确保子类不会随便覆盖单例行为,我们可以使用一种技巧,即CRTP(Curiously Recurring Template Pattern)。这种模式使得基类能够访问派生类的私有和保护成员,从而允许我们在基类中实现单例逻辑,并且保证派生类不会破坏这个逻辑。

以下是一个使用CRTP实现的单例基类的例子:

#include <iostream>  
#include <memory>  
#include <mutex>  
  
template<typename Derived>  
class SingletonBase {  
private:  
    static std::shared_ptr<Derived> instance_;  
    static std::mutex mtx_;  
  
    SingletonBase() = default;  
    SingletonBase(const SingletonBase&) = delete;  
    SingletonBase& operator=(const SingletonBase&) = delete;  
  
protected:  
    // 提供给派生类访问的静态方法,用于获取单例实例  
    static std::shared_ptr<Derived> getInstanceDerived() {  
        std::lock_guard<std::mutex> lock(mtx_);  
        if (!instance_) {  
            instance_.reset(new Derived());  
        }  
        return instance_;  
    }  
  
public:  
    // 虚析构函数,允许安全删除通过基类指针指向的派生类对象  
    virtual ~SingletonBase() = default;  
  
    // 提供给派生类覆盖的单例获取方法,返回基类指针  
    static std::shared_ptr<SingletonBase> getInstance() {  
        return std::static_pointer_cast<SingletonBase>(getInstanceDerived());  
    }  
};  
  
// 初始化静态成员变量  
template<typename Derived>  
std::shared_ptr<Derived> SingletonBase<Derived>::instance_ = nullptr;  
template<typename Derived>  
std::mutex SingletonBase<Derived>::mtx_;  
  
// 示例派生类  
class MySingleton : public SingletonBase<MySingleton> {  
public:  
    void doSomething() {  
        std::cout << "Doing something in MySingleton" << std::endl;  
    }  
};  
  
int main() {  
    // 获取单例实例并调用方法  
    auto mySingleton = MySingleton::getInstance();  
    mySingleton->doSomething();  
  
    // 尝试直接实例化MySingleton会失败,因为构造函数是私有的  
    // MySingleton ms; // 编译错误  
  
    return 0;  
}

在这个实现中,SingletonBase 是一个模板类,它接受一个派生类 Derived 作为模板参数。这个基类有一个私有的静态成员变量 instance_ 来保存单例实例,以及一个私有的静态互斥锁 mtx_ 来保证线程安全。getInstanceDerived() 是一个提供给派生类访问的静态方法,用于创建和返回派生类的单例实例。

getInstance() 方法返回一个基类指针,这允许我们保持单例接口的一致性,即使派生类可能添加额外的功能。注意,我们使用了 std::shared_ptr 来管理单例实例的生命周期,这可以自动处理内存释放,并且允许多个指针指向同一个实例。

由于 SingletonBase 的构造函数、拷贝构造函数和赋值运算符都是私有的或删除的,因此派生类无法直接创建或复制 SingletonBase 的实例。getInstanceDerived() 方法只能被 SingletonBase 和其派生类访问,因此派生类不能覆盖这个方法来破坏单例的逻辑。

这样,通过继承 SingletonBase<MySingleton>MySingleton 类自动成为了一个线程安全的单例类,而无需担心子类会覆盖关键的单例行为。

标签:std,SingletonBase,基类,C++,instance,单例,派生类
From: https://www.cnblogs.com/music-liang/p/18085177

相关文章

  • Python设计模式,可以采用单例模式+工厂方法吗?
    背景:今天看卡尔的设计模式,突然间,觉得可以把单例模式+工厂方法结合起来。不知道能不能行,咨询下AI,觉得可以。就mark一下问题:python中我有一个项目,有4个场景,我想创建一个基类,然后写4个具体实现的工厂,并继承这个基类,我为了防止这个基类创建多次,我是不是可以用单例模式?也就说我可......
  • 美国政府敦促开发者:停止使用 C、C++
    “C、C++不安全,新应用开发时就别用了,旧应用应该采取迁移行动”,近日,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的19页PDF报告中强烈呼吁道。其直言,C和C++这几种编程语言既缺乏与内存安全相关的特性,又在关键系统中大量使用,可......
  • C/C++开发问题总结
    1.结构体sizeof问题Linux支持指定结构体比特字段,Windows不支持指定结构体比特字段structindex{longlongstart=0;longlongend=0;unsignedlonglongix=0;shortsegment=0;unsignedshortt:2;unsignedlonglongseq:(64-18);......
  • C++ 函数重载
    一组函数,函数名相同。函数的参数类型或参数个数不同,那么这一组函数就称作函数重载。C++为什么支持函数重载?C++代码产生函数符号的时候,是由函数名+参数列表组成的;C代码产生函数符号的时候,是由函数名来决定;函数重载需要注意什么?一组函数如果是重载函数,一定是处于同一作用......
  • C++ 泛型编程
    1.函数模板假设我们设计一个交换两个整型变量的值的函数,代码如下://交换两个整型变量的值的Swap函数:voidSwap(int&x,int&y){inttmp=x;x=y;y=tmp;}如果是浮点类型的变量的值交换,则替换int类型为double即可,代码如下://交换两个double型变量......
  • C++ Qt开发:QUdpSocket实现组播通信
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QUdpSocket组件实现基于UDP的组播通信。组播是一种一对多的通信方式,允许一个发送者将数......
  • C++ string和const char*
    两种方式的函数声明如下:voidfunc(constchar*s);voidfunc(conststd::string&s);当实参是string时:voidfuncstr(conststd::string&s){ std::cout<<s;}voidfuncchar(constchar*s){ std::cout<<s;}intmain(){ std::strings("f......
  • C++:基本知识
    ......
  • 单例模式
    TS实现单例模式classAxios{//由于instance是一个静态属性,它会在整个应用程序的生命周期内保持存在,除非显式地将其设置为null或通过其他方式清除它的引用。privatestaticinstance:Axios|null=nullurl:stringtimeout:number//通过把构造函数设为私......
  • C++数据结构考研chapter5树(更新ing)
    一、概念1.结点2.边3.根4.叶子结点5.分支结点6.子树二、术语1.结点之间的关系描述(1)祖先(2)子孙(3)双亲(父)(4)孩子(5)兄弟(6)堂兄弟(7)路径自上而下(8)路径长度经过了几条边2.结点、树的属性描述(1)结点的层次(深度)从上到下数,默认从1开始,看题目要求(2)结点的高度从下到上......