在C ++ 11中根据派生类`operator ==`定义基类`operator ==`?

时间:2013-05-28 12:38:40

标签: c++ c++11

假设我有一个类型层次结构:

struct B { ... };

struct D1 : B { ... };
struct D2 : B { ... };
...
struct Dn : B { ... };

每个Di都有自己的operator==定义:

struct Di : B
{
    bool operator==(const Di&) const { ... }
    ...
};

我现在要定义B operator==,以便:

struct B
{
    bool operator==(const B& that) const
    {
        // psuedo-code
        let i, such the dynamic type of this is Di
        let j, such the dynamic type of that is Dj

        if (i != j)
            return false;
        else
            return Di::operator==(this, that);
    }
 }

组织这个或写这个的最佳方法是什么?

(最终目标是我想使用值类型为B *的标准容器类型(例如std::set<B*>),但是当它们来自时,它使用自定义Di::operator==s相同的派生类)

2 个答案:

答案 0 :(得分:6)

在基类中定义受保护的虚函数。使其成为纯虚拟,以确保每个子类Di提供实现。该函数将知道强制转换的目标,因为它属于Di。从基类中的运算符==调用该函数,并让它执行比较,如下所示:

struct B {
    bool operator==(const B& that) const {
        return this->equals(that);
    }
protected:
    virtual bool equals(const B& other) const=0;
};
struct D1 {
protected:
    virtual bool equals(const B& other) const {
        D1 *that = dynamic_cast<D1*>(&other);
        if (!that) return false;
        // Perform D1-specific comparison here.
        // You can use the == operator of D1, but you do not have to:
        return (*this) == (*that);
    }
};

此构造的作用是使==运算符虚拟的实现。

答案 1 :(得分:1)

以下是dasblinkenlight solution的略有变化,附加了功能(例如代码重复次数减少)

#include <typeinfo> // for typeid

struct B {

  bool operator==(const B& that) const {

    if (this == &that) // trivially equal
      return true;

    if (typeid(*this) != typeid(that)) // trivially different
      return false;

    return equals(that); // delegates to the virtual function
  }

  // polymorphic classes must have virtual destructors
  virtual ~B() = default;

protected:

  virtual bool equals(const B& that) const = 0;

};

struct D1 : B {

  bool operator ==(const D1& that) const {
    // ...
  }

private:

  // private because this function is not meant to be called except through
  // B::equals
  bool equals(const B& that) const override {
    // static_cast is safe here because execution only gets here if the
    // dynamic type of that is D1 (this was tested in B::operator =()
    return *this == static_cast<const D1&>(that);
  }

};