我在自己的代碼中多次被這個請求咬了。我將介紹一個簡單的例子:
struct Fruit
{
virtual bool is_equal(Fruit const & f) const = 0; // Compare two fruits
// Some dangerous actions:
bool operator==Fruit const & f)
{
return is_equal(f); // Dispatch!
}
};
struct Strawberry : public Fruit
{
bool is_equal(Fruit const & f)
{
bool equal = false;
// The f could be any fruit, such as tomatoes or pineapples or bananas.
// Need to perform a dynamic_cast to verify that the f is a strawberry.
Strawberry const & s = dynamic_cast<Strawberry const &>(f);
// perform strawberry comparison;
return equal;
};
}
struct Banana : public Fruit
{
bool is_equal(Fruit const & f)
{
bool equal = false;
// The f could be any fruit, such as tomatoes or pineapples or strawberries.
// Need to perform a dynamic_cast to verify that the f is a banana.
Banana const & b = dynamic_cast<Banana const &>(f);
// perform banana comparison;
return equal;
};
}
bool Compare_Fruits(Fruit const * pf1, Fruit const * pf2)
{
if (*pf1 == *pf2)
{
cout << "Fruits are equal\n";
return true;
}
cout << "Fruits are different\n";
return false;
}
int main(void)
{
// Fun with fruit.
Fruit * p_fruit_1 = new Strawberry;
Fruit * p_fruit_2 = new Banana;
Fruit * p_fruit_3 = new Strawberry;
// Is this valid, comparing two different fruits, when
// we just want to compare two strawberries?
if (Compare_Fruits(p_fruit_1, p_fruit_3)) // OK, both are strawberries
{
// ...
}
if (Compare_Fruits(p_fruit_1, p_fruit_2)) // Not OK, two different fruits.
{
// ...
}
return 0;
}
這裏的關鍵是,如果要實現在基類中的相同操作,使後代可以比較的情況下,你做了個錯誤的決定。請注意,我可以將指向一個後代(草莓)的實例的指針傳遞給另一個後代(香蕉)的比較方法,因爲相等函數基於指向基類的指針。不幸的是,沒有辦法知道派生自基類的後代有多少或全部。
對於編程安全性,我強烈建議不要將虛擬比較運算符放在基類中。基類應該有比較運算符,聲明爲protected,只比較基礎數據成員。這種方法將由後代調用。
請注意,引用類型的'dynamic_cast'可能會引發異常。可能會更好地轉換爲指針,如果指針返回NULL,您可能只想返回「false」。 – 2014-09-26 20:53:48
也許使用在成員變量'm_i'的基類中虛擬的getter? – abiessu 2014-09-26 20:53:54
閱讀關於雙派遣和關於它的古典解決方案 - 模式訪問者。 – Ilya 2014-09-26 20:56:55