动态转换还是函数重载?

发布于 2024-12-05 05:00:35 字数 1132 浏览 1 评论 0原文

考虑以下抽象类:

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++ 类型转换对我来说是一个相对神秘的话题。此外,哪种解决方案更“标准”,第二种解决方案对性能有任何影响吗?

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

Consider the following abstract class:

class Abstract {
public:
    // ...

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

    // ...
};

Now suppose I'm creating multiple derived classes from this abstract class. However, each one uses a different algorithm when comparing with its own type, and a generic algorithm when comparing with any of the other derived classes. Between the following two options, which would be the better, more efficient option?

Option 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
    }

    // ...
};

Option 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
        }
    }
};

I'm really curious as to what advantages and disadvantages these options would have, as C++ typecasting is a relatively mysterious topic to me. Furthermore, which solution is more "standard", and does the second solution have any impacts on performance?

Is there possibly a third solution? Especially if there were many derived classes, each needing its own special comparison algorithm against different derived classes?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

落日海湾 2024-12-12 05:00:35

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

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

Your two methods are for different situation. For option A, the static type of rhs is used to decide which function to call, and for option B the dynamic type is used.

So if you want your program to choose its behavior base on the "real" type of the argument, I think you should choose the second option. If types can be known at compile time, option A should be used since it gives better performance.

幸福丶如此 2024-12-12 05:00:35

我认为如果您希望 == 运算符使用参数的动态类型,那么选项 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

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

I think that option B is what you are looking for if you're expecting the == operator to use the dynamic type of the argument. For example:

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;
}

This prints:

0

So operator ==( const base& other ) gets called, even if the actual dynamic type is derived.

懷念過去 2024-12-12 05:00:35

实际上,您可以使用其中一种技术来实现第三种方式来实现双重调度。 “更有效的 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

You actually can do it third way using one of the techiniques to implement double dispatching. This approach is fully described in Item 31 of "More Effective C++". Here is small example:

#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;
}

Output:

1
0
墨落成白 2024-12-12 05:00:35

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

Unfortunately C++ have no multimethods that would choose the current function to call based on dynamic type information. You need double dispatch, visitor pattern or some other trick to implement the behavior.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文