【发布时间】:2019-06-06 23:54:26
【问题描述】:
使用 RTTI(通过使用 typeid 和 dynamic_cast)几乎被普遍认为是糟糕的编程习惯。
同样,定义一个所有导数都必须通过虚函数返回的类型标签也被认为是不好的做法,例如:
enum Type {
DERIVED_1,
DERIVED_2
};
class Base {
virtual Type type() = 0;
};
class Derived1 : public Base {
Type type() override {
return DERIVED_1;
}
};
class Derived2 : public Base {
Type type() override {
return DERIVED_2;
}
};
但是,有时我需要区分不同的派生类,例如当我有一个指向 Base 的指针时,它可能是 Derived1 或 Derived2:
Base *b = new Derived2();
// Approach 1:
if (typeid(*b) == typeid(Derived1)) {
std::cout << "I have a Derived1.\n";
} else if (typeid(*b) == typeid(Derived2)) {
std::cout << "I have a Derived2.\n";
}
// Approach 2:
if (b->type() == DERIVED_1) {
std::cout << "I have a Derived1.\n";
} else if (b->type() == DERIVED_2) {
std::cout << "I have a Derived2.\n";
}
人们说基于类型的决策树是不好的做法,但有时这是必要的!
假设我正在编写一个编译器,需要决定是否可以将给定的表达式分配给:
/* ... */
Expr* parseAssignment(Expr *left) {
// Is "left" a type of Expr that we can assign to?
if (typeid(*left) == typeid(VariableExpr)) {
// A VariableExpr can be assigned to, so continue pasrsing the expression
/* ... */
} else {
// Any other type of Expr cannot be assigned to, so throw an error
throw Error{"Invalid assignment target."};
}
}
(假设 Expr 是基类,VariableExpr 是派生类)
有没有其他方法可以实现这种不被认为是坏习惯的行为?或者在这种情况下 RTTI/虚函数和类型标签可以吗?
【问题讨论】:
-
即使是令人恐惧和鄙视的
goto也有很好的用途。 -
对不起,为什么 RTTI 被认为很差?你还有什么?好的编程是在正确的地方使用正确的东西,而不是仅仅因为你被告知使用或不使用某物而使用或不使用某物。
-
正确的问题通常不是“这种方法是好是坏”,而是“有没有更好的方法来完成我的任务?”在这种情况下,更好的方法通常是虚拟方法。
-
在这个例子中,我认为最好将解析器更改为明确地只允许赋值左侧的变量,但总的来说我同意R Sahu's answer。