派生类中的 Operator== 永远不会被调用
有人可以请让我摆脱这痛苦吗?我试图弄清楚为什么派生运算符==永远不会在循环中被调用。为了简化示例,这是我的基类和派生类:
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 的运算符 == ,但是当我循环列表时,将指针列表中的项目与 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==
即使两者对象是派生
的。
我知道当我发现问题所在时我会踢自己,但如果有人能温和地让我失望,我将不胜感激。
Can someone please put me out of my misery with this? I'm trying to figure out why a derived operator== never gets called in a loop. To simplify the example, here's my Base and Derived class:
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 );
};
Now when I instantiate and compare like this ...
Derived p1("Sarah", 42);
Derived p2("Sarah", 42);
bool z = ( p1 == p2 );
... all is fine. Here the operator== from Derived gets called, but when I loop over a list, comparing items in a list of pointers to Base objects ...
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;
Here asString()
(which is virtual and not shown here for brevity) works fine, but obj1 == obj2
always calls the Base
operator==
even if the two objects are Derived
.
I know I'm going to kick myself when I find out what's wrong, but if someone could let me down gently it would be much appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
那是因为您尚未将运算符==设为虚拟,因此在运行时不会考虑实际类型。
不幸的是,仅仅将operator==虚拟化并不能解决你的问题。原因是,当您通过将参数类型从基类更改为派生类来更改函数签名时,您实际上是在创建一个新函数。听起来您想研究 double-dispatch 来解决您的问题。
That's because you haven't made your operator== virtual so the actual type is not taken into account at runtime.
Unfortunately, just making the operator== virtual is not going to solve your problem. The reason why is that when you change the function signature by changing the type of the argument from base to derived, you are actually creating a new function. It sounds like you want to look into double-dispatch to solve your problem.
有两种方法可以解决这个问题。
第一个解决方案。我建议在循环中添加一些额外的类型逻辑,以便您知道何时有
Base
以及何时有Derived
。如果您确实只处理Derived
对象,请使用其他方式将
dynamic_cast
放置在某处。第二种解决方案。将相同类型的逻辑放入您的
operator==
中。首先将其设为虚拟,以便在运行时确定左侧操作数的类型。然后手动检查右侧操作数的类型。但考虑到不同类型的对象可能不相等,可能你想要的是
There are two ways to fix this.
First solution. I would suggest adding some extra type logic to the loop, so you know when you have a
Base
and when you have aDerived
. If you're really only dealing withDerived
objects, useotherwise put a
dynamic_cast
somewhere.Second solution. Put the same kind of logic into your
operator==
. First make it virtual, so the type of the left-hand operand is determined at runtime. Then manually check the type of the right-hand operand.but considering that objects of different types probably won't be equal, probably what you want is
您需要使
operator==
virtual
并且需要确保它们两个方法具有相同的签名。即他们可能需要都采用Base
。您的派生类中可以有一个能够处理派生对象的重载operator==
。You need to make
operator==
virtual
and you need to make sure that they both methods have the same signature. i.e. they will likely need to both takeBase
. You could have an overloadedoperator==
in your derived class that would be able to handle Derived objects.当成员函数是虚拟的时,虚拟表在运行时用于多态地调用指针实际指向的类型(在本例中为您的类 Derived)上的函数。当函数不是虚拟的时,不会进行虚拟表查找,并且会调用给定类型的函数(在本例中为您的类 Base)。
在这里,您的operator=()函数不是虚拟的,因此使用指针的类型而不是指针指向的类型。
When a member function is virtual, the virtual table is used at runtime to polymorphically call the function on the type that the pointer actually points to (in this case, your class Derived). When a function is not virtual, no virtual table lookup is done and the function the given type is called (in this case, your class Base).
Here, your operator=() functions are not virtual, so the type of the pointer is used rather than the type that the pointer points to.
对于要使用自己的运算符实现的派生类,该运算符在基类中必须是虚拟的,否则将使用基类实现。
For derived classes to use their own implementation of an operator the operator must be virtual in the base class, otherwise the base classes implementation will be used instead.