如何解决如果两个不相关的类型共享一个共同的可能未知的子类,是否可以在两个不相关的类型之间进行动态转换?
很抱歉,如果问题标题没有意义,但我不确定如何简洁地描述我正在尝试解决的问题。问题来了:
- 我正在使用一个 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();
这也没有问题。我可以通过执行 doSomething()
来调用我的自定义 static_cast
方法。但是……我现在需要拥有多个可能的 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.
*/
我卡住了。请注意,无论我从库中收到哪个 doSomething()
类,我的函数 Custom<>
都将具有相同的行为。我最初的想法是将我的 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*
,但编译器不知道这一点,而且我猜无法执行正确的指针调整来转换 {{1} }} 到 Base*
。在这一点上,我被卡住了,不知道该怎么做。我需要对从库中获得的任何 Interface*
调用我的 doSomething()
函数,但我不知道我实际上获得了哪个自定义子类。我目前看到的唯一解决方案是对每个可能的子类穷举Base*
。
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>
等类,他们必须记住返回并更新 if-else 链以彻底检查每种可能的情况。所以我的问题是:
- 是否有可能以某种方式在
Custom<Child5>
对象上调用我的doSomething()
函数,而无需实际知道我在编译时拥有哪个Base*
类,并且无需简单地尝试所有可能的 {{1} }?因此,我的问题的标题是:我能否以某种方式将Custom<>
转换为dynamic_cast
,因为我知道他们共享一个共同的子类(我只是不知道哪个 子类)。 - 我是否以完全错误的方式处理这个问题?
解决方法
你应该使用 dynamic_cast<Interface*>(base)
struct B{virtual ~B(){}};
struct I{virtual int foo()=0;};
struct X:B{};
struct Y:I,X{virtual int foo(){return 10;}};
struct Z:I,X{virtual int foo(){return 20;}};
int main(){
B* x = new Z;
I* i = dynamic_cast<I*>(x);
return i->foo();
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。