2014-09-26 66 views
0

我想实现一个函数来比较派生类。但是我发现我必须将基类对象转换为派生类对象。如何实现一个虚函数equal()

有没有办法避免使用强制转换或其他更好的设计来实现比较功能?

class A { 
    public : 
     virtual bool equal(const A & obj) const = 0; 
}; 

class AA : public A{ 
    public: 
     AA (int i) : m_i(i) {} 
     virtual bool equal(const A & obj) const 
     { 
      return m_i == dynamic_cast<const AA&>(obj).m_i; 
     } 

    private: 
     int m_i; 
}; 

int main() { 
    AA aa1(10), aa2(9); 
    A &a1 = aa1, &a2 = aa2; 

    a1.equal(a2); 

    return 0; 
} 
+2

请注意,引用类型的'dynamic_cast'可能会引发异常。可能会更好地转换为指针,如果指针返回NULL,您可能只想返回“false”。 – 2014-09-26 20:53:48

+0

也许使用在成员变量'm_i'的基类中虚拟的getter? – abiessu 2014-09-26 20:53:54

+0

阅读关于双派遣和关于它的古典解决方案 - 模式访问者。 – Ilya 2014-09-26 20:56:55

回答

0

我在自己的代码中多次被这个请求咬了。我将介绍一个简单的例子:

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,只比较基础数据成员。这种方法将由后代调用。

+0

然后如何如果你有一对只有基类指针或引用的对象,你会知道它们是否相等? – 2014-09-26 21:33:17

+0

如果通过基类指针或引用已知的两个对象只能使用基类的数据进行比较。只有当两个对象是同一类的实例时,才能比较内容相等性。同样,当基类是“Life_Form”,一个实例是树而另一个实例是蜘蛛时,正在比较什么?这没有意义。在我的项目中,Field是一个基类,我有一个'Record',它是'Field'的一个容器。我如何确定我没有将'Field :: Text'与'Field :: Double'进行比较? – 2014-09-27 00:14:43

+0

在问题中显示的虚拟比较函数中使用'dynamic_cast',您可以轻松地将比较函数放在基类上 - 您无法在其中实现*函数。 – 2014-09-27 00:41:35

相关问题