使用虚函数与dynamic_cast

using virtual function vs dynamic_cast

本文关键字:dynamic cast 函数      更新时间:2023-10-16

与其使用虚函数,不如使用类似的东西:

void BaseClass::functionName () {  // BaseClass already has virtual functions
    // some LONG code true for all derived classes of BaseClass
    // ...
    if (typeid (*this) == typeid (DerivedClass1))
        // use functions of DerivedClass1 on dynamic_cast<DerivedClass1*>(this)
    else if (typeid (*this) == typeid (DerivedClass2))
        // use functions of DerivedClass2 on dynamic_cast<DerivedClass2*>(this)
    // some LONG code true for all derived classes of BaseClass
    // ...
 }
只是

我觉得将虚函数用于上述内容不是一个好主意,因为它只是专门用于派生类的一小部分。 然后,需要对所有派生类一遍又一遍地使用用于所有派生类的长代码(建议为此使用帮助程序函数)。 当然,我已经测试了我的方法并且它有效(我想没有性能损失),但我想知道这是否是有问题的做法。如果 if-else-if 部分在函数中多次使用怎么办?

如果所有派生类的通用代码都是相对短的,那么最好使用虚函数,对吧?

为什么不这样做:

void BaseClass::functionName () {
    // some LONG code true for all derived classes of BaseClass
    // ...
    this->some_protected_virtual_member_function();
    // some LONG code true for all derived classes of BaseClass
    // ...
 }

因此,公共部分不会重复,并且该行为仍然可以轻松地在子类中具有扩展,而无需向父类添加另一个if

除非类具有虚函数,否则您的代码根本无法工作。C++ 只提供有限的反射:typeid(DerivedClass1)==typeid(DerivedClass2) 如果没有虚函数。上面的代码也可能比简单地访问虚拟函数慢:你会得到每种类型的新分支,而不是恒定的时间指针查找。

但是,上述代码的最大问题是它松散了多态性和封装性。使用代码必须知道 DerivedClass1 和 DerivedClass2 需要做什么。它需要了解 DerivedClass1 和 DerivedClass2 中的结构。此外,所有代码都堆积在一个地方,使此函数可能有数百行。

我认为您正在这里寻找模板方法模式: 只需使用您现有的非虚拟函数,并让它仅为具体类之间不同的一小部分代码调用虚函数。它的优点是看起来更漂亮。

void BaseClass::functionName () {
    // some LONG code true for all derived classes of BaseClass
    // ...
    functionName_impl();  // Will be virtual (private or protected) and overriden in each child class to do the right work.
    // some LONG code true for all derived classes of BaseClass
    // ...
 }

这是模板方法模式的退化情况:

class Base {
public:
    void templated() {
        // do some stuff
        this->hook1();
        // other stuff
        if (/*cond*/) { this->hook2(); }
        size_t acc = 0;
        for (Stuff const& s: /*...*/) { acc += this->hook3(s); }
        // other stuff
    }
private:
    virtual void hook1() {}
    virtual void hook2() {}
    virtual size_t hook3(Stuff const&) { return 0; }
}; // class Base

然后Derived类可以自定义钩子的行为。

警告:这本质上是非常严格的,因为templated方法不是virtual;这既是这种模式的优点,也是问题,这很好,因为如果您需要更改templated方法,那么它是在一个地方定义的,如果提供的钩子不足以自定义行为,那就很烦人了。