【问题标题】:C++ Dynamic Dispatch FunctionC++ 动态调度函数
【发布时间】:2020-06-27 05:38:58
【问题描述】:

我正在尝试创建一个重载函数,该函数将使用对象的动态类型调用。我尝试这样做干扰下面的实际类结构,因为我没有直接访问权限(即我无法添加虚拟方法等)

作为一个具体的例子,让我们考虑一个看起来有点像这样的 AST 类结构:

类 ASTNode {}; // 这个是完全抽象的;即有一个 virtual void method() = 0;

类分配:ASTNode {};
类表达式:ASTNode {};

类 StringExpr : 表达式 {};
类 MathExpr : 表达式 {};

我想编写一个函数act,它将ASTNode 的实例作为参数,并根据其实际动态类型做一些不同的事情。 调用将是这样的

std::shared_ptr<ASTNode> parsedAST = get_a_parsed_ASTNode(); // ... received from some parser or library
act(parsedAST);

然后,我要行动,取决于ASTNode的动态类型。

void act(std::shared_ptr expr)
{
  // 用数学表达式做一些事情,例如评估他们的价值
};

无效行为(std::shared_ptr expr)
{
  // 用字符串表达式做一些事情,例如将它们的值写入日志
};

无效行为(std::shared_ptr expr)
{
  // 对其他类型的表达式做一些事情(例如布尔表达式)
};

目前,我无法调用,因为它们的动态类型可能不是“最具体的类型”。相反,我必须手动创建一个调度程序,如下所示,但我认为该方法有点傻,因为它实际上除了调度之外什么都不做。

void act(std::shared_ptr node_ptr)
{
  if(std::shared_ptr derived_ptr = std::dynamic_pointer_cast(node_ptr))
  {
    行为(派生的_ptr);
  }
  否则 if(std::shared_ptr derived_ptr = std::dynamic_pointer_cast(node_ptr))
  {
    行为(派生的_ptr);
  }
  否则 if(std::shared_ptr derived_ptr = std::dynamic_pointer_cast(node_ptr))
  {
     // 用泛型表达式做一些事情。确保这是在更具体的 if casts 之后
  }
  else if( ... ) // 更多
  {
     
  }
  // 更多 else if
  别的
  {
     // 默认操作或引发无效参数异常等等...
  }
};

这特别烦人且容易出错,因为我的类层次结构中有许多 (> 20) 可以实例化的不同具体类。此外,我有各种act 函数,当我重构事物时(例如,为其他类型添加act),我必须确保注意调度程序中if(dynamic_pointer_cast) 的正确顺序。 而且它也不是那么稳定,因为底层类层次结构的更改将需要我直接更改每个调度程序,而不仅仅是特定的 act 函数。

是否有更好/更智能的解决方案?显然我很欣赏“原生”解决方案,但我也愿意考虑图书馆。

【问题讨论】:

  • 是只有基类不受你控制,还是部分派生类?如果您可以控制所有派生类,则可以使用 CRTP 方法。否则,您需要在代码中的某处拥有类型和类型的顺序。制作一个从列表生成调度函数的模板可能是一个更易于维护的选项。
  • 不幸的是,我无法控制整个类层次结构。 CRTP 看起来很有趣,但我认为它不太适合,除非我以某种方式通过创建双重继承结构来“隐藏”整个类层次结构,其中每个“影子”类都继承自 1. 原始类,2. 它是影子超级。然后我可以将我的逻辑添加到影子类中。但是,这仍然给我留下了需要维护的整个影子类层次结构。

标签: c++ c++11 polymorphism dispatch


【解决方案1】:

我自己从来没有遇到过这样的问题,但是可以想到以下解决方案。

创建模仿原始层次结构的层次结构,具有虚拟act,基具有基指针,并且每个都将其转换为相应的派生指针。

现在,要创建所需的包装器,您不需要正确排序的 dynamic_cast,发送 typeid 字符串。因此,您的调度是从字符串到包装器工厂的映射。

当然,typeid 字符串需要 RTTI,但dynamic_cast 也需要 RTTI。

【讨论】:

    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    • 2013-02-28
    • 1970-01-01
    相关资源
    最近更新 更多