【发布时间】:2021-04-14 18:58:24
【问题描述】:
对不起,如果问题标题没有意义,但我不确定如何简洁地描述我要解决的问题。问题来了:
- 我正在使用一个 C++ 库,它大量使用了一个我们称之为
Base的类 - 这个库有几个不同的子类继承自
Base。我们将这些类称为Child1、Child2、.. 等。 - 此库允许用户创建自己的
Base子类,并让库使用这些类的实例。我目前有这样的事情:
class Custom : public Child1 // inherit from Child1, which inherits from Base
{
public:
// override virtual functions here
// ...
void doSomething(); // Utility function I created
}
然后我正在使用的库将具有如下功能:
void foo(Base* base);
我可以传入指向我的Custom 类的指针,没问题,一切都很好。有时我可能需要从库中接收一个指向 Base 对象的指针并用它做一些事情。看起来像这样:
// code...
Base *base = getSomeBase(); // getSomeBase() is a function from the library that returns a Base*
Custom* myCustom = static_cast<Custom*>(base); // I always make the library use my `Custom` class, so this is safe.
myCustom->doSomething();
这也可以正常工作。我可以通过执行static_cast 来调用我的自定义doSomething() 方法。但是......我现在需要拥有不止一个可能的Custom 类。具体来说,我需要创建适当的“子”类以从我的Custom 类中的模板参数继承。我的代码现在看起来像这样:
template <class Child_t>
class Custom : public Child_t // inherit from Child_t, which inherits from Base
{
public:
// override virtual functions here
// ...
void doSomething(); // Utility function I created
}
让库使用我的新模板Custom<> 类没有问题,因为只要模板参数Child_t 实际上是从Base 继承的库的子类之一,我的Custom<> 类可以简单地转换为Base*。尝试朝另一个方向发展时会出现问题:
Base *base = getSomeBase();
/* ?????
Would like to call base->doSomething();
But I have no idea which Custom class I have received here. "base" could be
a Child1*, Child2*, etc. There's no way for me to perform a cast.
*/
我被困住了。请注意,无论我从库中收到哪个 Custom<> 类,我的函数 doSomething() 都将具有相同的行为。我最初的想法是将我的 doSomething() 函数移动到接口类。
class Interface
{
public:
virtual void doSomething() = 0;
}
然后让每个Custom<> 类像这样实现接口:
template <class Child_t>
class Custom : public Child_t, public Interface
{
void doSomething() override;
}
这最终没有帮助,因为编译器不允许我执行以下操作:
Base *base = getSomeBase();
Interface* interface = static_cast<Interface*>(base); // Error: can't static_cast between unrelated types.
interface->doSomething();
编译器说Interface 和Base 是不相关的类型。我知道我收到的任何Base* 实际上都是Interface*,但编译器不知道这一点,而且我猜,无法执行正确的指针调整以将Base* 转换为@987654354 @。在这一点上,我被卡住了,不知道该怎么做。我需要在从库中获得的任何Base* 上调用我的doSomething() 函数,但我不知道我实际获得的是哪个自定义子类。我目前看到的唯一解决方案是将dynamic_cast 穷尽所有可能的子类。
Base *base = getSomeBase(); // getSomeBase()
if (auto* c1 = dynamic_cast<Custom<Child1>*>(base))
{
c1->doSomething();
}
else if (auto* c2 = dynamic_cast<Custom<Child2>*>(base))
{
c2->doSomething();
}
这是一个丑陋的解决方案。它还给开发人员带来了额外的认知负担,因为如果他们在任何时候决定他们需要使用Custom<Child3>、Custom<Child4>、Custom<Child5> 等类,他们必须记住返回并更新 if-else 链详尽地检查每种可能的情况。所以我的问题是:
- 是否有可能以某种方式调用
Base*对象上的doSomething()函数,而实际上不知道我在编译时有哪个Custom<>类,并且不简单地尝试所有可能的dynamic_cast?因此我的问题的标题是:我可以以某种方式将Base*转换为Interface*,因为我知道他们共享一个共同的子类(我只是不知道哪个子类)。 - 我是否以完全错误的方式处理这件事?
【问题讨论】:
-
dynamic_cast<Interface*>(base)? -
...或者如果只有一个可能的
Interface,我会考虑有机会将各种virtual void doSomething() = 0;直接放在Base中,避免多重继承和动态转换。将Base向下转换为Custom以调用专用方法的初始方法听起来很可疑,我将审查导致该方法的设计决策 -
@MatG 是的,理想情况下接口应该在
Base。但是Base是一个来自我正在链接的库的类,我没有完整的源代码(只有 .h 文件和 .lib 文件)。所以我不能修改Base来包含doSomething()函数。
标签: c++ templates polymorphism dynamic-cast static-cast