![](/img/trans.png)
[英]Implementing the assignment operator in an abstract base class using the curiously recurring template pattern (CRTP)
[英]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
rhs
和rhs
是同一類型,因此我們終於可以進行實際比較了。 一串if
語句用於返回符合Java的Comparable
和C的qsort()
語義的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.