对从给定超类继承的所有 类 调用虚函数
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> _;
我正在尝试在我的 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> _;