如果两个不相关的类型共享一个共同的可能未知的子类,是否可以在两个不相关的类型之间进行动态转换?

如何解决如果两个不相关的类型共享一个共同的可能未知的子类,是否可以在两个不相关的类型之间进行动态转换?

很抱歉,如果问题标题没有意义,但我不确定如何简洁地描述我正在尝试解决的问题。问题来了:

  1. 我正在使用一个 C++ 库,该库大量使用了一个我们称之为 Base 的类
  2. 这个库有几个不同的继承自 Base 的子类。我们将这些类称为 Child1Child2、.. 等。
  3. 此库允许用户创建自己的 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();

编译器说 InterfaceBase 是不相关的类型。我知道我收到的任何 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 链以彻底检查每种可能的情况。所以我的问题是:

  1. 是否有可能以某种方式在 Custom<Child5> 对象上调用我的 doSomething() 函数,而无需实际知道我在编译时拥有哪个 Base* 类,并且无需简单地尝试所有可能的 {{1} }?因此,我的问题的标题是:我能否以某种方式将 Custom<> 转换为 dynamic_cast,因为我知道他们共享一个共同的子类(我只是不知道哪个 子类)。
  2. 我是否以完全错误的方式处理这个问题?

解决方法

你应该使用 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();
}

http://coliru.stacked-crooked.com/a/f7a5787cb9fe80be

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?