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

时间:2019-01-18 22:08:40

标签: c++ casting tree interpreter

作为大学的课程工作,我正在用c ++编写口译员。 基本上,我是使用Google自己将this python interpreter转换为c ++。

使用访问者作为口译员,我有2个课程

BinOp : public AST

Number : public AST

我的口译课上有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;
}

Interpreter继承的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函数并使用 here

中提到的这种方法
void *handle = dlsym(0, RTLD_LOCAL | RTLD_LAZY);
FunctionType *fptr = (FunctionType *)dlsym(handle, "visitBinOp/visitNumber");
fptr();

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

2 个答案:

答案 0 :(得分:0)

注意:尽管有时可能需要a0IrBTg6zcI,但要注意使用它是一种“代码异味”。

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

那么为什么不只给dynamic_cast<>一个AST方法,然后制作

virtual unsigned long InterpreterVisit(Interpreter* interpreter)
代替?如果要将解释器代码与AST代码分开,还可以将其实现为附件,在该实例中,第二个对象由实现unsigned long Interpreter::visit(AST *node) { node->InterpreterVisit(this); } 的AST节点拥有,并且那么您只需要一个位置即可为此类型创建正确类型的附件对象(例如,使用部分模板特化)。

我对您的解释器的结构了解得不够多,无法说出它对您的设计是否有用,但是我想鼓励您停下来思考一下,是否有比InterpreterVisit()更好的方法了试图使用它。

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

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

  1. 正向声明使用dynamic_cast<>(请注意分号)而不包括其标头所涉及的类之一。这将告诉C ++,存在该名称的类,而无需拉入整个标头及其对其他类的使用。您不能声明前向声明类的子类,但是您可以 声明对它的引用和指针。

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

  3. 自己拆分课程。即有一个需要包含零件类.cpp的类MixinA,另一个需要包含零件类A的类MixinB,然后创建B。这样一来,您的班级既可以做到,又可以避免出现圆圈,因为只有class C : public MixinA, public MixinB ...才能看到整个图片。

答案 1 :(得分:-1)

好,今天早上我醒了。 我没有在无法访问Interpreter函数的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