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
相关产品推荐
相关产品推荐

