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

基于CRTP的Meyers单例模板实现:如何让子类直接调用instance()方法?

当然可以实现!你当前的代码里,Foo是私有继承Singleton<Foo>的,所以Singleton<Foo>的instance()方法在Foo内部是私有访问权限,外部无法直接通过Foo::instance()调用。我们可以通过几种方式解决这个问题,下面逐个说明:

方案1:在子类中添加转发的静态instance()方法

这是最直接的方式,不需要修改Singleton模板,只需要在Foo中新增一个静态方法,直接转发到Singleton<Foo>::instance():

#include <bits/stdc++.h>
template <typename T>
class Singleton {
public:
    static T& instance() {
        static T _instance;
        return _instance;
    }
protected:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton & s) = delete;
    Singleton& operator=(const Singleton & s) = delete;
};

class Foo : Singleton<Foo> {
public:
    // 添加转发方法
    static Foo& instance() {
        return Singleton<Foo>::instance();
    }

    void print() {
        std::cout<<"from the foo singleton count : " <<count++<<std::endl;
    }
private:
    int count = 0;
};

int main () {
    // 现在可以直接用 Foo::instance() 调用了
    Foo::instance().print();
    Foo::instance().print();
    Foo::instance().print();
    return 0;
}

优点:不需要改动原有Singleton模板的逻辑,保持了Foo私有继承的特性(隐藏了单例实现细节);缺点:每个单例子类都要重复写一遍这个转发方法,有点冗余。


方案2:将子类改为public继承Singleton<Foo>

如果不介意暴露Foo的单例实现方式,可以把继承权限改为public,这样Singleton<Foo>的public成员instance()会自动成为Foo的public成员:

// Singleton 模板代码不变
class Foo : public Singleton<Foo> { // 改为 public 继承
public:
    void print() {
        std::cout<<"from the foo singleton count : " <<count++<<std::endl;
    }
private:
    int count = 0;
};

int main () {
    Foo::instance().print(); // 直接调用即可
    return 0;
}

优点:代码最简洁,不需要额外添加任何方法;缺点:外部代码能看到Foo继承了Singleton模板,暴露了单例的实现细节。


方案3:使用using声明引入基类的instance()方法

这是平衡了代码简洁性和隐藏实现细节的最优解——保持私有继承,同时通过using声明把基类的instance()方法引入到子类的public作用域:

// Singleton 模板代码不变
class Foo : Singleton<Foo> {
public:
    // 把基类的 instance() 引入到当前类的 public 域
    using Singleton<Foo>::instance;

    void print() {
        std::cout<<"from the foo singleton count : " <<count++<<std::endl;
    }
private:
    int count = 0;
};

int main () {
    Foo::instance().print(); // 正常调用
    return 0;
}

优点:既保持了私有继承(隐藏实现细节),又不需要写冗余的转发代码,代码简洁且优雅;缺点:需要了解using声明的作用(不过这是C++中很常用的特性)。

以上三种方案都能实现你想要的Foo::instance().print()调用方式,你可以根据自己的需求选择最合适的一种。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:43:13