有人请能让我摆脱苦难吗?我试图弄清楚为什么派生运算符==永远不会在循环中被调用。为了简化示例,这是我的Base和Derived类:
class Base { // ... snipped
bool operator==( const Base& other ) const { return name_ == other.name_; }
};
class Derived : public Base { // ... snipped
bool operator==( const Derived& other ) const {
return ( static_cast<const Base&>( *this ) ==
static_cast<const Base&>( other ) ? age_ == other.age_ :
false );
};
现在当我像这样实例化和比较......
Derived p1("Sarah", 42);
Derived p2("Sarah", 42);
bool z = ( p1 == p2 );
......一切都很好。这里调用了来自Derived的operator ==,但是当我遍历列表时,将指针列表中的项目与Base对象进行比较......
list<Base*> coll;
coll.push_back( new Base("fred") );
coll.push_back( new Derived("sarah", 42) );
// ... snipped
// Get two items from the list.
Base& obj1 = **itr;
Base& obj2 = **itr2;
cout << obj1.asString() << " " << ( ( obj1 == obj2 ) ? "==" : "!=" ) << " "
<< obj2.asString() << endl;
此处asString()
(这是虚拟的,为简洁起见未在此处显示)正常,但obj1 == obj2
总是甚至调用Base
operator==
如果这两个对象是Derived
。
我知道当我发现什么是错的时候我会踢自己,但如果有人能让我轻轻放下,我将非常感激。
答案 0 :(得分:9)
那是因为你没有让你的算子==虚拟,所以在运行时不考虑实际的类型。
不幸的是,只是让运营商==虚拟无法解决您的问题。原因是当您通过将参数的类型从base更改为derived来更改函数签名时,实际上是在创建一个新函数。听起来你想要调查double-dispatch来解决你的问题。
答案 1 :(得分:4)
有两种方法可以解决这个问题。
第一个解决方案。我建议在循环中添加一些额外的类型逻辑,以便知道何时有Base
以及何时有Derived
。如果您真的只处理Derived
个对象,请使用
list<Derived*> coll;
否则将dynamic_cast
放在某处。
第二种解决方案。将相同类型的逻辑放入operator==
。首先使其成为虚拟,因此左侧操作数的类型在运行时确定。然后手动检查右侧操作数的类型。
virtual bool operator==( const Base& other ) const {
if ( ! Base::operator==( other ) ) return false;
Derived *other_derived = dynamic_cast< Derived * >( &other );
if ( ! other_derived ) return false;
return age_ == other_derived->age_;
}
但是考虑到不同类型的对象可能不相等,可能你想要的是
virtual bool operator==( const Base& other ) const {
Derived *other_derived = dynamic_cast< Derived * >( &other );
return other_derived
&& Base::operator==( other )
&& age_ == other_derived->age_;
}
答案 2 :(得分:2)
您需要制作operator==
virtual
,并且需要确保它们两种方法都具有相同的签名。即他们可能需要同时采取Base
。您可以在派生类中重载operator==
,以便能够处理派生对象。
答案 3 :(得分:1)
当成员函数是虚拟的时,虚拟表在运行时用于多态调用指针实际指向的类型的函数(在本例中为您的类Derived)。当一个函数不是虚函数时,不会进行虚拟表查找,并且调用给定类型的函数(在本例中为您的类Base)。
这里,您的operator =()函数不是虚函数,因此使用指针的类型而不是指针指向的类型。
答案 4 :(得分:0)
对于派生类使用自己的运算符实现,运算符必须在基类中是虚拟的,否则将使用基类实现。