【问题标题】:Dynamic Casts or Function Overloads?动态强制转换或函数重载?
【发布时间】:2011-09-17 02:32:56
【问题描述】:

考虑以下抽象类:

class Abstract {
public:
    // ...

    virtual bool operator==(const Abstract& rhs) const = 0;

    // ...
};

现在假设我正在从这个抽象类创建多个派生类。但是,在与自己的类型进行比较时,每个都使用不同的算法,在与任何其他派生类进行比较时使用通用算法。在以下两个选项之间,哪个是更好、更有效的选项?

选项 A:

class Derived : public Abstract {
public:
    // ...

    bool operator==(const Abstract& rhs) const {
        // Code for comparing to any of the other derived classes
    }

    bool operator==(const Derived& rhs) const {
        // Code for comparing to myself
    }

    // ...
};

选项 B:

class Derived : public Abstract {
public:
    // ...

    bool operator==(const Abstract& rhs) const {
        const Derived* tmp = dynamic_cast<const Derived*>(&rhs);
        if (tmp) {
            // Code for comparing to myself
        }
        else {
            // Code for comparing to any of the other derived class
        }
    }
};

我真的很好奇这些选项有什么优点和缺点,因为 C++ 类型转换对我来说是一个相对神秘的话题。此外,哪种方案更“标准”,第二种方案对性能有影响吗?

可能有第三种解决方案吗?特别是如果有很多派生类,每个派生类都需要针对不同派生类的特殊比较算法?

【问题讨论】:

    标签: c++ inheritance casting overloading dynamic-cast


    【解决方案1】:

    您的两种方法适用于不同的情况。对于选项 A,rhs 的静态类型用于决定调用哪个函数,对于选项 B,使用动态类型。

    因此,如果您希望您的程序根据参数的“真实”类型选择其行为,我认为您应该选择第二个选项。如果可以在编译时知道类型,则应使用选项 A,因为它提供了更好的性能。

    【讨论】:

    • 那么dynamic_cast其实性能开销比较高?
    • @teedayf,相对较高是轻描淡写。好吧,更严重的是,只要您不将dynamic_cast 用于对性能至关重要的事情,您就不必担心。
    【解决方案2】:

    如果您希望 == 运算符使用参数的动态类型,我认为选项 B 就是您正在寻找的。例如:

    class base
    {
    public:
      virtual bool operator ==( const base& other ) = 0;
    };
    
    class derived : public base
    {
    public:
      bool operator ==( const base& other ) { return false; }
      bool operator ==( const derived& other ) { return true; }
    };
    
    
    int main()
    {
      base* a = new derived;
      base* b = new derived;
      std::cout << ( *a == *b ) << std::endl;
    }
    

    打印出来:

    0
    

    所以 operator ==( const base& other ) 被调用,即使实际的动态类型是派生的

    【讨论】:

    • 我明白了。这个例子就是我所追求的。虽然我相信选项 A 会更适合我的特定需求,因为我希望能够控制使用哪种算法,即使对象可能不是正确的类型,这个例子也准确地展示了我是如何做到这一点的。谢谢!
    【解决方案3】:

    您实际上可以使用其中一种技术以第三种方式实现双重调度。这种方法在“更有效的 C++”的第 31 条中有完整的描述。这是一个小例子:

    #include <iostream>
    
    class Derived1;
    class Derived2;
    
    class Base
    {
    public:
        virtual bool operator==( Base& other) = 0;
        virtual bool compare( Base& other) {return false;}
        virtual bool compare( Derived1& other) {return false;}
        virtual bool compare( Derived2& other) {return false;}
    };
    
    class Derived1 : public Base
    {
    public:
        virtual bool operator==( Base& other) {return other.compare(*this);}
    
        virtual bool compare( Base& other) {return false;}
        virtual bool compare( Derived1& other) {return true;}
    };
    
    class Derived2 : public Base
    {
    public:
        virtual bool operator==( Base& other) {return other.compare(*this);}
    
        virtual bool compare( Base& other) {return false;}
        virtual bool compare( Derived2& other) {return true;}
    };
    
    int main()
    {
        Base *a = new Derived1;
        Base *b = new Derived1;
        Base *c = new Derived2;
    
        std::cout << (*a == *b) << std::endl;
        std::cout << (*a == *c) << std::endl;
        return 0;
    }
    

    输出:

    1
    0
    

    【讨论】:

      【解决方案4】:

      不幸的是,C++ 没有多种方法可以根据动态类型信息选择要调用的当前函数。您需要双重调度、访问者模式或其他一些技巧来实现该行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-15
        • 2010-10-07
        • 1970-01-01
        • 2012-12-27
        • 2012-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多