对从给定超类继承的所有 类 调用虚函数

Calling a virtual function on all classes inheriting from a given superclass

我正在尝试在我的 C++ 应用程序中实现用户默认设置。 为此,我创建了一个接口 class,其中包含一个函数:

class IRegisterUserDefaults
{
public:
    IRegisterUserDefaults();
    virtual void registerUserDefaults(){}
};

每个class继承自该接口class将实现注册需要设置的用户默认值的功能。

到目前为止没问题。但是最好的调用方式是什么? 我来自 Objective-C,在那里我可以搜索所有 classes 并找到实现接口并调用它们的 registerUserDefaults 函数的那些。我知道 C++ 没有这种级别的内省。每个 class 调用一次函数就足够了(因此使其成为静态的)。

Objective

如果 class subclasses IRegisterUserDefaults 调用函数 "automatically" 就好了。我尝试从 IRegisterUserDefaults 构造函数调用该方法,但它看起来没有正确调用 subclass 函数。有办法实现吗?

此外,确保每个 class 仅调用一次的最佳方法是什么?

在子 class 构造函数中调用方法,您不能在基 class 构造函数中调用此方法,因为那时子 class 尚未构造。

这对你有用吗?

#include <iostream>
#include <string>

class IRegisterUserDefaults
{
public:
    IRegisterUserDefaults() {}
    virtual void registerUserDefaults() = 0;
};

class MoreDerivedRegisterUserDefaults : public IRegisterUserDefaults
{
public:
    MoreDerivedRegisterUserDefaults (int x, int y) : m_x (x), m_y (y) { }
    virtual void registerUserDefaults() override {
        std::cout << "MoreDerivedRegisterUserDefaults::registerUserDefaults called (" << m_x << ", " << m_y << ")" << std::endl;
    }
private:
    int m_x, m_y;
};

template <class T, typename... Args> void RegisterDefaultsHandler (Args... args) {
    T obj (args...);
    obj.registerUserDefaults ();
}    

int main ()
{
    RegisterDefaultsHandler<DerivedRegisterUserDefaults> ();
    RegisterDefaultsHandler<MoreDerivedRegisterUserDefaults> (1, 2);
    // ...
}

您必须实例化每个派生的 class 某处

直播demo(已更新)。输出:

DerivedRegisterUserDefaults::registerUserDefaults called
MoreDerivedRegisterUserDefaults::registerUserDefaults called (1, 2)

编辑: 与@Caleth 交谈后,我稍微调整了代码以使我的意图更清晰。

编辑 2: 添加了 Variadiac 模板,结果比我想象的要简单,很有用 'howto' 指南 here.

IRegisterUserDefaults 不是一个有意义的接口,在 任何 语言中。

听起来您要解决的实际问题是"run some code once, at or near class first use"。你可以用这样的东西来做到这一点

class HasUserDefaults {
    static std::once_flag register_once;
    void registerUserDefaults() { /*...*/ }
public:
    HasUserDefaults ()
    { 
      // in all the constructors
        std::call_once(register_once, &HasUserDefaults::registerUserDefaults, this);
    }

    // other members
};

您是否有一个位置,所有这些派生的 classes 都是已知的?在那种情况下,在那里做:

// The type-list can be used in many ways, as you need
using all_classes = std::tuple<A, B, C, D /* and so on */>;

template <class... Ts>
static void register_all_classes(Y<Ts...>*)
{ ((Ts().registerUserDefaults()), ...); }

register_all_classes((all_classes*)nullptr);

否则,你显然必须去中心化:

是否有一个单独的编译单元负责注册每个 class?在这种情况下,请使用名称空间范围的对象。也许为此使用助手:

template <class T>
struct Init {
    Init() { T().registerUserDefaults(); }
};

// Used in single TU as:
static Init<SomeRegisterUserDefaults> _;

否则,看看std::ios_base::Init <iostream> 是怎么做到的。我简化了,因为不需要指示 uninit:

template <class T>
struct MultiInit {
    MultiInit() { static Init<T> _; }
};

// Used in any number of TUs as:
static MultiInit<SomeRegisterUserDefaults> _;