C动态对象类比较

C动态对象类比较,第1张

概述我希望能够比较表达式的语法树.基类Expr有一个纯虚拟比较方法,用于覆盖的具体子类: class Expr {public: virtual bool compare(const Expr *other) const = 0;}; 例如,NumExpr和AddExpr是两个具体的子类,分别用于表示文字整数表达式和二进制加法表达式.每个比较方法所做的第一件事是使用dynamic_cast来确 我希望能够比较表达式的语法树.基类Expr有一个纯虚拟比较方法,用于覆盖的具体子类:

class Expr {public:  virtual bool compare(const Expr *other) const = 0;};

例如,NumExpr和AddExpr是两个具体的子类,分别用于表示文字整数表达式和二进制加法表达式.每个比较方法所做的第一件事是使用dynamic_cast来确保另一个表达式具有相同的类型:

class NumExpr : public Expr {  int num;public:  NumExpr(int n) : num(n) {}  bool compare(const Expr *other) const {    const NumExpr *e = dynamic_cast<const NumExpr*>(other);    if (e == 0) return false;    return num == e->num;  }};class AddExpr : public Expr {  Expr *left,*right;public:  AddExpr(Expr *l,Expr *r) : left(l),right(r) {}  bool compare(const Expr *other) const {    const AddExpr *e = dynamic_cast<const AddExpr*>(other);    if (e == 0) return false;    return left->compare(e->left) && right->compare(e->right);  }};

当我使用dynamic_cast时,我总觉得我做错了什么 –
是否有更合适的方法来执行对象之间的动态比较
不使用dynamic_cast?

使用visitor design pattern并不能解决对RTTI的需求(据我所知). “表达式访问者”的抽象基类可能如下所示:

class NumExpr;class AddExpr;class ExprVisitor {public:  virtual voID visit(NumExpr *e) {}; // "do nothing" default  virtual voID visit(AddExpr *e) {};};

表达式的基类包括纯虚拟接受方法:

class Expr {public:  virtual voID accept(ExprVisitor& v) = 0;};

具体的表达式子类然后使用double dispatch来调用适当的访问方法:

class NumExpr : public Expr {public:  int num;  NumExpr(int n) : num(n) {}  virtual voID accept(ExprVisitor& v) {    v.visit(this);  };};class AddExpr : public Expr {public:  Expr *left,*right;  AddExpr(Expr *l,right(r) {}  virtual voID accept(ExprVisitor& v) {    v.visit(this);  };};

当我们最终使用这种机制进行表达式比较时,我们仍然需要使用RTTI(据我所知);例如,以下是用于比较表达式的示例访问者类:

class ExprCompareVisitor : public ExprVisitor {  Expr *expr;  bool result;public:  ExprCompareVisitor(Expr *e) : expr(e),result(false) {}  bool getResult() const {return result;}  virtual voID visit(NumExpr *e) {    NumExpr *other = dynamic_cast<NumExpr *>(expr);    result = other != 0 && other->num == e->num;  }  virtual voID visit(AddExpr *e) {    AddExpr *other = dynamic_cast<AddExpr *>(expr);    if (other == 0) return;    ExprCompareVisitor vleft(other->left);    e->left->accept(vleft);    if (!vleft.getResult()) return;    ExprCompareVisitor vright(other->right);    e->right->accept(vright);    result = vright.getResult();  }};

注意我们仍在使用RTTI(dynamic_cast就是这种情况).

如果我们真的希望避免RTTI,我们可以“自己动手”创建独特的常量来识别每个具体的表达风格:

enum ExprFlavor {  NUM_EXPR,ADD_EXPR};class Expr {public:  const ExprFlavor flavor;  Expr(ExprFlavor f) : flavor(f) {}  ...};

每种具体类型都会适当地设置它:

class NumExpr : public Expr {public:  int num;  NumExpr(int n) : Expr(NUM_EXPR),num(n) {}  ...};class AddExpr : public Expr {public:  Expr *left,Expr *r) : Expr(ADD_EXPR),left(l),right(r) {}  ...};

然后我们可以使用static_cast和flavor字段来避免RTTI:

class ExprCompareVisitor : public ExprVisitor {  Expr *expr;  bool result;public:  ExprCompareVisitor(Expr *e) : expr(e),result(false) {}  bool getResult() const {return result;}  virtual voID visit(NumExpr *e) {                                                                    result = expr->flavor == NUM_EXPR && static_cast<NumExpr *>(expr)->num == e->num;  }  ...};

这个解决方案似乎只是复制了RTTI在幕后所做的事情.

解决方法 假设您在编译时不知道任何一方的动态类型(例如静态类型与动态类型相同)并且您实际上想要通过指针或引用比较两个Expr对象,那么您将要去必须进行两次虚拟调用(双重调度)或使用dynamic_cast.

它看起来像这样:

class Expr {public:  virtual bool compare(const Expr *other) const = 0;  virtual bool compare(const NumExpr *other) const { return false; }  virtual bool compare(const AddExpr *other) const {return false;}};class NumExpr : public Expr {  int num;public:  explicit NumExpr(int n) : num(n) {}  bool compare(const Expr *other) const {    return other->compare(this);  }  bool compare(const NumExpr *other) const {    return num == other->num;  }};
总结

以上是内存溢出为你收集整理的C动态对象类比较全部内容,希望文章能够帮你解决C动态对象类比较所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1226429.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存