【发布时间】:2021-06-22 13:20:11
【问题描述】:
我有一个想法,可以通过可变参数模板继承以更好的方式构建经典实体组件。这个问题源于 3d 图形背景下的时髦实验,但我相信我已经把它分解为一个关于 C++ 的非常抽象的问题。我能够在 Microsoft cl aka 中当前实现的范围内使用 C++20。 MSVC++19-工具链。
所以。一些基类:
class basic {
public:
std::wstring get_name() { return name; }
virtual void do_something_idk_virtual() = 0;
virtual ~basic() {}
private:
std::wstring name;
}
class has_legs {
public:
virtual void walk() = 0;
virtual ~has_legs() {}
}
class has_wings {
public:
virtual void fly() = 0;
virtual ~has_wings() {}
}
template<typename... Ts>
class entity : public basic, public Ts... {
public:
virtual ~entity() {}
}
到目前为止,一切都很好。现在我想做一只鸭子:
class duck : entity<has_wings, has_legs> {
public:
virtual ~duck() {}
virtual void walk() { cout << "walk" << endl; }
virtual void fly() { cout << "fly" << endl; }
virtual void do_something_idk_virtual() { } // nothing,
}
仍然,似乎工作。问题是:我知道有数据结构(比如linked_list,或某种图表),我使用访问者模式来处理basic*-typed 的东西。我现在有很多看起来像这样的代码。从字面上看,这是我的程序的核心和关键部分:
void visit(basic* node) {
//here i find out, through magic or some other kind of out-of-scope-mechanism that node is at least a has_wings. Problem:
reinterpret_cast<has_wings*>(node)->fly(); //does not work, will call basic::do_something_idk_virtual(). As far as i understand, this is because the compiler-generated vtable does not change via the reinterpret_cast.
reinterpret_cast<entity<has_wings>*>(node)->fly(); //might, work, problems start to come in if node is of some type that has_wings and has_legs. It sometimes calls some other method, depending on the ordering in declaring the class.
}
解决方案
- 让每个组件(又名纯接口)和
entity-class 虚拟继承自basic - 在
basic中添加非虚拟方法:
template<typename TComponent> TComponent* get_component() {
return dynamic_cast<TComponent*>(this);
}
这将修复 vtables。我不知道为什么 dynamic_cast 会那样做。
【问题讨论】:
-
你混合了静态和动态调度,现在两者都有缺点!
-
如果你有一个
basic*的数据结构,那么你应该只对它们进行basic操作。如果你想做has_wings的操作,那么你还应该有一个has_wings*的数据结构。 -
这就是
dynamic_cast所做的。 -
dynamic_cast甚至不会在这里编译,因为在has_wings和basic之间没有可能的有效转换,尽管它可能适用于basic到entity<has_wings>- 检查。跨度> -
是的,所以它编译但抛出运行时异常,因为
entity<has_wings>不是duck的超类
标签: c++ polymorphism variadic-templates c++20