普遍认为使用RTTI(通过使用typeiddynamic_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的指针,该指针可能是Derived1Derived2时:

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 /虚拟功能和类型标签?

最佳答案

使用dynamic_cast不仅可以,而且在许多情况下也是必不可少的。

当我看到类似的代码时,将使用Open-Closed Principle作为指导。

如果在向系统添加新的派生类型时必须重新访问if-else块或enum,我认为这是一个问题。如果没有,我不认为这是一个问题。

当您看到级联的if-else代码块时,通常会违反Open-Closed Principle,应避免使用。避免这种情况的方法是使用回调机制。


让基类具有注册派生类型的回调函数的函数。
在基类的业务逻辑中,检查是否已为派生类型注册了功能。如果是,请调用该函数。如果不是,则要么默默地忽略它,要么需要引发异常。

关于c++ - 使用RTTI(或返回类型标签的虚拟函数)是否还可以?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54157031/

10-12 15:01
查看更多