繁体   English   中英

C++ 如何转换动态派生类

[英]C++ How to cast dynamically derived classes

我正在用 C++ 编写一个解释器作为大学的课程工作。 基本上我正在使用谷歌自己将这个python解释器翻译成c++。

使用访问者作为口译员我有 2 个班级

BinOp : public AST

Number : public AST

我的 Interpreter 类中有 2 个方法

class Interpreter : public NodeVisitor

int visitBinOp(BinOp* node)
{
  //example if the operation is +
  //return this->visit(node->left) + this->visit(node->right)
}
int visitNumber(Number* node)
{
  //returns the int value that's in the node.
  //return node->value;
}

和解释器继承的 NodeVisitor 中的 1 个方法

class NodeVisitor
int visit(AST* node)
{

  //if node is BinOp properFunction is pointer to visitBinOp

  //if node is Number properFunction is pointer tp visitNumber

  //return properFunction(node)
}

问题 1 :检查 AST 是 BinOp 还是 Number 的最佳方法是什么

if(typeid(node) == typeid(BinOp*)

或者通过一些转换(尝试 dynamic_cast 时我得到错误,类不是多态的)。

主要问题:我需要以某种方式创建指向这些函数的指针,但不知道如何创建。

编辑 1将此代码添加到 NodeVisitor 但由于它包括“Interpreter.h”和解释器包括“NodeVisitor.h”我得到

错误 C2504:“NodeVisitor”:未定义基类。

unsigned long int NodeVisitor::visit(AST* node)
{
  std::function<unsigned long int(Number* node)> visitNumber = std::bind(&Interpreter::VisitNumber);
  std::function<unsigned long int(BinaryOperation* node)> visitBinOp = std::bind(&Interpreter::VisitBinOp);
  if (typeid(node) == typeid(Number*))
  {
    visitNumber((Number*)node);
  }
  if (typeid(node) == typeid(BinaryOperation*))
  {
    visitBinOp((BinaryOperation*)node);
  }
}

我想我需要将 extern "C" 添加到 visitBinOp 和 visitNumber funcs 并使用这里提到的这种方法

void *handle = dlsym(0, RTLD_LOCAL | RTLD_LAZY);
FunctionType *fptr = (FunctionType *)dlsym(handle, "visitBinOp/visitNumber");
fptr();

但我不太确定这是如何工作的。

注意:虽然有时可能需要dynamic_cast<> ,但请注意,使用它是一种“代码味道”。

在面向对象的编程中,您通常不会询问对象的类型,然后根据该信息执行某些操作。 你告诉对象做你需要做的事情,它会根据它是什么对象做正确的事情。

那么为什么不给AST一个virtual unsigned long InterpreterVisit(Interpreter* interpreter)方法,并让

unsigned long Interpreter::visit(AST *node) {
    node->InterpreterVisit(this);
}

反而? 如果您想将解释器代码与 AST 代码分开,您也可以将其实现为附件,其中您有一个由 AST 节点拥有的实现InterpreterVisit() ,然后您只需要一个点来创建这种类型的附件对象的正确类型(例如使用部分模板特化)。

我不太了解你的解释器的结构,无法说明这是否适用于你的设计,但我想鼓励你停下来思考是否有比dynamic_cast<>更好的方法,当你想使用它时。

有时它也可以帮助“隐藏”演员表的使用,特别是如果你发现自己经常做同样的演员表。 提前做一次。 将对象附加到基于该转换的对象,然后调用该对象而不是一遍又一遍地转换。

PS:关于您的通函包含,有时您可以避免这种情况。 存在多种工具:

  1. 使用class Foo;向前声明所涉及的class Foo; (注意分号)而不是包括其标题。 这将告诉 C++ 存在一个具有该名称的类,而无需拉入整个头文件及其对另一个类的使用。 您不能声明前向声明类的子类,但可以声明对它的引用和指针。

  2. 拆分您的标题。 通常每个类都有自己的头文件( .h / .hpp )和实现文件( .cp / .cpp )。 这样,您可以只包含您需要的类,并在其他类的头文件中预先声明这些类(然后实际上只在使用这些类的实现文件中包含完整的头文件)。

  3. 自己拆分你的班级。 即有一个类MixinA需要包含部分类A需要包含另一个类MixinB和部分类B需要包含,然后创建class C : public MixinA, public MixinB ... 这样你就有了一个既能做这两种事情的类,又要避开圆圈,因为只有C才能看到整个画面。

好的,今天早上我醒来时得到了答案。 我没有在 NodeVisitor.cpp 中实现访问函数,在那里我无法访问解释器函数,而是将访问函数设为虚拟并在 Interpreter.cpp 中实现它

unsigned long int Interpreter::visit(AST* node)
{
  Number* number = dynamic_cast<Number*>(node);
  BinaryOperation* binOp = dynamic_cast<BinaryOperation*>(node);

  if (number)
  {
    return this->VisitNumber((Number*)node);
  }

  return this->VisitBinOp((BinaryOperation*)node);
}

我想我的大脑只是需要休息一下......在工作中编码 8 小时,然后在家里 4 小时,即连续 12 小时:D

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM