簡體   English   中英

在抽象基類上實現operator <

[英]Implementing operator< on abstract base class

我有一個類型層次結構,我不確定實現operator<operator==的干凈/好方法。

本質上,我已經有了:

class Parent {
    public:
        virtual ~Parent() {}
};

class A : public Parent { int         data; };
class B : public Parent { double      data; };
class C : public Parent { std::string data; };

bool operator==(A const & lhs, A const & rhs) { return lhs.data == rhs.data; }
bool operator< (A const & lhs, A const & rhs) { return lhs.data <  rhs.data; }

bool operator==(B const & lhs, B const & rhs) { return lhs.data == rhs.data; }
bool operator< (B const & lhs, B const & rhs) { return lhs.data <  rhs.data; }

bool operator==(C const & lhs, C const & rhs) { return lhs.data == rhs.data; }
bool operator< (C const & lhs, C const & rhs) { return lhs.data <  rhs.data; }

我也想實現的是:

bool operator==(Parent const & lhs, Parent const & rhs) { ... }
bool operator< (Parent const & lhs, Parent const & rhs) { ... }

我目前已經通過執行以下操作來實現它:

bool operator==(Parent const & lhs, Parent const & rhs) {
    try {
        return dynamic_cast<A const &>(lhs) == dynamic_cast<A const &>(rhs);
    } catch(std::bad_cast const & e) {
    }

    try {
        return dynamic_cast<B const &>(lhs) == dynamic_cast<B const &>(rhs);
    } catch(std::bad_cast const & e) {
    }

    try {
        return dynamic_cast<C const &>(lhs) == dynamic_cast<C const &>(rhs);
    } catch(std::bad_cast const & e) {
    }

    assert(typeid(lhs) != typeid(rhs));
    return false;
}

但這似乎很糟糕。 有沒有更清潔的方法來解決這個問題?

對於復雜類型的比較,您可能會發現Double Dispatch非常有用。

如果您的類型非常簡單,將它們全部合為一體有時會很有效。 在3個無符號變量的示例中,最好只使用一種類型來容納所有大小,並避免動態分配和更復雜的類型圖。


適用於原始問題; 其中A,B和C都使用了無符號類型:

好吧,一種快速而骯臟的方法是:

class Parent {
protected:
  virtual ~Parent() {}
public:
  bool operator<(const Parent& pOther) const {
    return this->as_uint64() < pOther.as_uint64();
  }
  // ...
private:
  // using a type which accommodates all values
  virtual uint64_t as_uint64() const = 0;
};

然后從Parent派生將采用以下形式:

class A : public Parent {
// ...
private:
    virtual uint64_t as_uint64() const { return this->data; }
private:
    uint16_t data;
};

那么Parent可以簡單地定義所有比較器,並且所有Parent類型都是可比較的。

將虛擬比較器用於單次調度,將dynamic_cast用於類型轉換:

class ABC_base {
public:
    virtual ~ABC_base() {} 
    bool operator < (ABC_base const & rhs) const {
        return this->comparator(rhs) < 0;
    }
protected:
    virtual int comparator (ABC_base const &) = 0;
};

class ABC : public ABC_base {
protected:
    virtual int comparator(ABC_base const & rhs) const {
        try {
            return my_comparator(dynamic_cast<ABC const&>(rhs));
         // Run-time cast failed - use double dispatch as fallback
         } catch (std::bad_cast&) {
             return -rhs.comparator(*this);
         }
     }
private:
    int my_comparator(ABC const & rhs) const {
        if (data < rhs.data)
            return -1;
        if (data == rhs.data)
            return 0;
        if (data > rhs.data)
            return 1;
    }
    T data;
};

代碼的工作方式如下:

基類的operator <被調用,它使用動態查找來找到comparator 它檢查返回的值,看是否較小。

派生類的比較器嘗試向下轉換基類引用,以便可以在派生類的成員上進行比較。

為什么使用基類引用,而不使用派生類引用? 由於功能簽名不正確,虛擬分派將無法正常工作。

如果向下轉換成功,它將調用非虛擬專用比較器。 否則,它將再次使用虛擬分派來執行(rhs ? *this)並取反結果以補償反向排序。

為什么不在一個虛擬函數中進行強制轉換和比較? 因為該函數將執行兩件事,所以它將使代碼更加混亂:強制轉換比較。 因此,有一個專用比較器功能。 如果要在派生類中使用基函數,請遵循class ABC_der : public ABC ,調用ABC::comparator(static_cast<ABC const&>(rhs)) 使用Base::強制進行靜態分派,因此您不必公開輔助程序比較功能。

現在, this rhsrhs是同一類型,因此我們終於可以進行實際比較了。 一串if語句用於返回符合Java的Comparable和C的qsort()語義的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM