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

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

本文关键字:调用 函数 超类 继承      更新时间:2023-10-16

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

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

从此接口类继承的每个类都将实现该函数来注册需要设置的用户默认值。

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

目的

如果一个类子类 IRegisterUserDefaults 时"自动"调用该函数,那就太好了。我尝试从 IRegisterUserDefaults 构造函数调用该方法,但看起来这不能正确调用子类函数。有没有办法做到这一点?

另外,确保每个类只调用一次的最佳方法是什么?

IRegisterUserDefaults

在任何语言中都不是一个有意义的界面。

听起来您尝试解决的实际问题是"在类首次使用时或接近类时运行一次代码"。你可以用这样的东西来做到这一点

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
};

您是否有一个已知所有这些派生类的位置?在这种情况下,请在此处执行:

// 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);

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

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

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> _;

这对你有用吗?

#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);
// ...
}

您必须在某处实例化每个派生类。

现场演示(更新(。 输出:

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

编辑:在与@Caleth交谈后,我对代码进行了一些调整,以使我的意图更加清晰。

编辑2:添加了Variadiac模板,结果比我想象的要容易,有用的"操作方法"指南在这里。

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