4

次の抽象クラスについて考えてみます。

class Abstract {
public:
    // ...

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

    // ...
};

ここで、この抽象クラスから複数の派生クラスを作成していると仮定します。ただし、それぞれが独自のタイプと比較する場合は異なるアルゴリズムを使用し、他の派生クラスと比較する場合は一般的なアルゴリズムを使用します。次の2つのオプションのうち、どちらがより良い、より効率的なオプションでしょうか?

オプション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 ++型キャストは私にとって比較的不思議なトピックであるため、これらのオプションにどのような長所と短所があるのか​​、私は本当に興味があります。さらに、どちらのソリューションがより「標準的」であり、2番目のソリューションはパフォーマンスに影響を与えますか?

おそらく3番目の解決策はありますか?特に、派生クラスが多数あり、それぞれが異なる派生クラスに対して独自の特別な比較アルゴリズムを必要としている場合はどうでしょうか。

4

4 に答える 4

2

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.

于 2011-09-17T02:43:49.097 に答える
1

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.

于 2011-09-17T02:50:47.773 に答える
1

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
于 2011-09-17T08:35:16.483 に答える
0

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.

于 2011-09-18T00:39:54.563 に答える