如果两个不相关的类型共享一个公共(可能未知)child class,是否可以 dynamic_cast?
Is it possible to dynamic_cast between two unrelated types, if they share a common (possibly unknown) child class?
抱歉,如果问题标题没有意义,但我不确定如何简洁地描述我要解决的问题。这是问题所在:
- 我正在使用大量使用 class 的 C++ 库,我们称之为
Base
- 这个库有几个不同的 child class 继承自
Base
。我们将这些 class 称为 Child1
、Child2
、.. 等等
- 此库允许用户创建他们自己的 child classes of
Base
并让库使用这些 classes 的实例。我目前有这样的东西:
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
class 没问题,一切都很好。有时我可能需要从库中接收指向 Base
object 的指针并用它做一些事情。看起来像这样:
// 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
class。具体来说,我需要制作适当的“child”class 以从我的 Custom
class 中的模板参数继承。我的代码现在看起来像这样:
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<>
class 没有问题,因为只要模板参数 Child_t
实际上是库的 child class继承自 Base
的 es,我的 Custom<>
class 可以简单地转换为 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<>
class,我的函数 doSomething()
都将具有相同的行为。我最初的想法是将我的 doSomething()
函数移动到接口 class.
class Interface
{
public:
virtual void doSomething() = 0;
}
然后让每个 Custom<>
class 像这样实现接口:
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*
到 Interface*
。在这一点上,我被困住了,不知道该怎么做。我需要在从图书馆获得的任何 Base*
上调用我的 doSomething()
函数,但我不知道我实际获得的是哪个自定义 child class。我目前看到的唯一解决方案是穷举 dynamic_cast
到所有可能的 child class.
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>
等 class,他们必须记住返回并更新 if-else 链以详尽检查每种可能的情况。所以我的问题是:
- 是否有可能以某种方式在
Base*
object 上调用我的 doSomething()
函数,而实际上不知道我在编译时有哪个 Custom<>
class,而不是简单地尝试所有可能的 dynamic_cast
?因此我的问题的标题是:我能以某种方式将 Base*
转换为 Interface*
,因为我知道它们共享一个共同的 child class(我只是不知道哪个 child class).
- 我是不是用完全错误的方式来解决这个问题?
你应该使用 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();
}
抱歉,如果问题标题没有意义,但我不确定如何简洁地描述我要解决的问题。这是问题所在:
- 我正在使用大量使用 class 的 C++ 库,我们称之为
Base
- 这个库有几个不同的 child class 继承自
Base
。我们将这些 class 称为Child1
、Child2
、.. 等等 - 此库允许用户创建他们自己的 child classes of
Base
并让库使用这些 classes 的实例。我目前有这样的东西:
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
class 没问题,一切都很好。有时我可能需要从库中接收指向 Base
object 的指针并用它做一些事情。看起来像这样:
// 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
class。具体来说,我需要制作适当的“child”class 以从我的 Custom
class 中的模板参数继承。我的代码现在看起来像这样:
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<>
class 没有问题,因为只要模板参数 Child_t
实际上是库的 child class继承自 Base
的 es,我的 Custom<>
class 可以简单地转换为 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<>
class,我的函数 doSomething()
都将具有相同的行为。我最初的想法是将我的 doSomething()
函数移动到接口 class.
class Interface
{
public:
virtual void doSomething() = 0;
}
然后让每个 Custom<>
class 像这样实现接口:
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*
到 Interface*
。在这一点上,我被困住了,不知道该怎么做。我需要在从图书馆获得的任何 Base*
上调用我的 doSomething()
函数,但我不知道我实际获得的是哪个自定义 child class。我目前看到的唯一解决方案是穷举 dynamic_cast
到所有可能的 child class.
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>
等 class,他们必须记住返回并更新 if-else 链以详尽检查每种可能的情况。所以我的问题是:
- 是否有可能以某种方式在
Base*
object 上调用我的doSomething()
函数,而实际上不知道我在编译时有哪个Custom<>
class,而不是简单地尝试所有可能的dynamic_cast
?因此我的问题的标题是:我能以某种方式将Base*
转换为Interface*
,因为我知道它们共享一个共同的 child class(我只是不知道哪个 child class). - 我是不是用完全错误的方式来解决这个问题?
你应该使用 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();
}