You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++多继承场景下抽象基类Application全局唯一单例实现咨询

可行实现方案

核心思路是把单例的全局唯一实例托管给抽象基类Application,提供一次性的初始化接口指定派生类类型,禁止重复初始化,同时限制派生类实例只能通过基类的初始化接口创建,满足全局仅存一个Application类型实例的要求。

具体实现步骤

1. 改造抽象基类Application

在基类中维护静态的全局实例指针,提供模板化的初始化接口和全局访问接口:

#include <stdexcept>
#include <type_traits>
#include <utility>
#include <cstdlib>

class Application {
public:
    // 全局获取实例的接口
    static Application& GetInstance() {
        if (!s_instance) {
            throw std::runtime_error("Application not initialized, call Init<T>() first");
        }
        return *s_instance;
    }

    // 模板化初始化接口,仅可调用一次
    template <typename Derived, typename... Args>
    static void Init(Args&&... args) {
        static_assert(std::is_base_of_v<Application, Derived>, "Derived must inherit from Application");
        if (s_instance) {
            throw std::runtime_error("Application can only be initialized once");
        }
        s_instance = new Derived(std::forward<Args>(args)...);
        // 注册程序退出时的销毁逻辑,避免内存泄漏
        std::atexit(Destroy);
    }

    // 禁止拷贝移动
    Application(const Application&) = delete;
    Application& operator=(const Application&) = delete;
    Application(Application&&) = delete;
    Application& operator=(Application&&) = delete;

    // 抽象类纯虚接口,根据业务需求定义
    virtual void Run() = 0;
protected:
    Application() = default;
    virtual ~Application() = default;

private:
    static Application* s_instance;
    static void Destroy() {
        delete s_instance;
        s_instance = nullptr;
    }
};

// 静态成员初始化
Application* Application::s_instance = nullptr;

2. 派生类实现

派生类将构造函数设为私有,声明基类的初始化接口为友元,禁止外部直接创建实例:

class SampleApplication : public Application {
    // 让基类的Init接口可以访问私有构造函数
    friend void Application::Init<SampleApplication>();
public:
    void Run() override {
        // 实现对应业务逻辑
    }
private:
    SampleApplication() = default;
    // 支持带参构造,Init接口会自动完美转发传入的参数
    // explicit SampleApplication(int port) : m_port(port) {}
};

class OtherSampleApplication : public Application {
    friend void Application::Init<OtherSampleApplication>();
public:
    void Run() override {
        // 其他派生类的业务实现
    }
private:
    OtherSampleApplication() = default;
};

3. 使用方式

在程序启动阶段调用一次Init接口指定要使用的派生类类型,之后全局通过GetInstance访问即可:

int main() {
    // 仅可调用一次,指定派生类类型,有构造参数直接往后传即可
    Application::Init<SampleApplication>();
    // 全局访问获取的是指定的派生类实例
    Application::GetInstance().Run();
    
    // 重复初始化会抛出异常,避免创建多个不同派生类的实例
    // Application::Init<OtherSampleApplication>();
    return 0;
}

方案说明

  • 完全满足需求:全局仅存在一个Application类型实例,实例实际类型可任意指定为继承自Application的派生类,抽象基类本身不会被实例化
  • 类型安全:初始化时会自动做派生类类型校验,非法类型编译期直接报错
  • 支持多线程扩展:如果需要在多线程环境下保证初始化安全,给Init接口加互斥锁即可

内容的提问来源于stack exchange,提问作者Daniel Marques

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:42:03