표현식에 대한 구문 트리를 비교할 수 있기를 원합니다. 기본 클래스 Expr
구체적인 서브 클래스가 오버라이드 (override) 할 수있는 순수 가상 compare
방법이있다 : 예를 들어C++ 동적 객체 클래스 비교
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);
}
};
난 항상 내가 뭔가 잘못하고있는 중이 야 기분 각 compare
방법을 수행하는 첫 번째 일은 확인 other
표현이 동일한 유형인지 확인하기 위해 dynamic_cast
를 사용하다 접근 방식을 통해 dynamic_cast
을 사용하지 않고도 객체 간의 동적 비교를 수행 할 수 있습니까?
visitor design pattern을 사용하면 이 아닌은 (내가 알 수있는 한) RTTI의 필요성을 해결합니다. 에 "표현의 방문자"에 대한 추상 기본 클래스는 다음과 같이 보일 수 있습니다
class Expr {
public:
virtual void accept(ExprVisitor& v) = 0;
};
구체적인 표현 서브 클래스가 두 번 를 사용
이class NumExpr;
class AddExpr;
class ExprVisitor {
public:
virtual void visit(NumExpr *e) {}; // "do nothing" default
virtual void visit(AddExpr *e) {};
};
표현의 기본 클래스는 순수 가상 accept
방법을 포함
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, Expr *r) : left(l), right(r) {}
virtual void accept(ExprVisitor& v) {
v.visit(this);
};
};
: 적절한 visit
메소드를 호출을 파견 마침내이 메커니즘을 사용하여 표현식 비교를 수행 할 때 여전히이 RTTI를 사용해야합니다 (가능한 한 알 수 있습니다). 우리는 여전히 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();
}
};
주 (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, *right;
AddExpr(Expr *l, Expr *r) : Expr(ADD_EXPR), left(l), right(r) {}
...
};
을
그리고 우리는 RTTI를 방지하기 위해 static_cast
과 flavor
필드를 사용할 수 있습니다
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가 수행중인 작업을 복제하는 것처럼 보입니다.
조회 ** 이중 발송 **. –
또는 방문자 디자인 패턴. –
'기본 표현식이 같은 경우'compare 함수가 true를 반환하고 다른 모든 경우에 false를 반환하는 것이 맞습니까? – user1055604