我在自己的代码中多次被这个请求咬了。我将介绍一个简单的例子:
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