派生类中的运算符==永远不会被调用

时间:2021-11-25 08:08:32

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:

有人可以请我摆脱我的痛苦吗?我试图找出为什么派生运算符==永远不会在循环中调用。为了简化示例,这是我的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 );
};

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 ...

... 一切皆好。这里调用了来自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;

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.

这里asString()(这是虚拟的,为简洁起见,此处未显示)工作正常,但obj1 == obj2总是调用Base运算符==即使两个对象都是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.

我知道当我发现什么是错的时候我会踢自己,但如果有人能让我轻轻放下,我将非常感激。

5 个解决方案

#1


4  

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 a Derived. If you're really only dealing with Derived objects, use

第一解决方案我建议在循环中添加一些额外的类型逻辑,这样你就知道什么时候你有一个Base,什么时候你有一个Derived。如果您真的只处理Derived对象,请使用

list<Derived*> coll;

otherwise put a dynamic_cast somewhere.

否则将dynamic_cast放在某个地方。

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.

二解决方案。将相同类型的逻辑放入运算符==。首先使其成为虚拟,因此左侧操作数的类型在运行时确定。然后手动检查右侧操作数的类型。

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_;
}

but considering that objects of different types probably won't be equal, probably what you want is

但考虑到不同类型的物体可能不相等,可能就是你想要的

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


9  

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来更改函数签名时,实际上是在创建一个新函数。听起来你想要调查双重调度来解决你的问题。

#3


2  

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 take Base. You could have an overloaded operator== in your derived class that would be able to handle Derived objects.

您需要使operator == virtual,并且您需要确保它们两个方法具有相同的签名。即他们可能需要同时采取基地。你可以在你的派生类中有一个能够处理Derived对象的重载operator ==。

#4


1  

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).

当成员函数是虚拟的时,虚拟表在运行时用于多态调用指针实际指向的类型的函数(在本例中,您的类Derived)。当函数不是虚函数时,不会进行虚拟表查找,并且调用给定类型的函数(在本例中为您的类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.

这里,您的operator =()函数不是虚函数,因此使用指针的类型而不是指针指向的类型。

#5


0  

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.

对于使用自己的运算符实现的派生类,运算符必须在基类中是虚拟的,否则将使用基类实现。

#1


4  

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 a Derived. If you're really only dealing with Derived objects, use

第一解决方案我建议在循环中添加一些额外的类型逻辑,这样你就知道什么时候你有一个Base,什么时候你有一个Derived。如果您真的只处理Derived对象,请使用

list<Derived*> coll;

otherwise put a dynamic_cast somewhere.

否则将dynamic_cast放在某个地方。

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.

二解决方案。将相同类型的逻辑放入运算符==。首先使其成为虚拟,因此左侧操作数的类型在运行时确定。然后手动检查右侧操作数的类型。

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_;
}

but considering that objects of different types probably won't be equal, probably what you want is

但考虑到不同类型的物体可能不相等,可能就是你想要的

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


9  

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来更改函数签名时,实际上是在创建一个新函数。听起来你想要调查双重调度来解决你的问题。

#3


2  

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 take Base. You could have an overloaded operator== in your derived class that would be able to handle Derived objects.

您需要使operator == virtual,并且您需要确保它们两个方法具有相同的签名。即他们可能需要同时采取基地。你可以在你的派生类中有一个能够处理Derived对象的重载operator ==。

#4


1  

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).

当成员函数是虚拟的时,虚拟表在运行时用于多态调用指针实际指向的类型的函数(在本例中,您的类Derived)。当函数不是虚函数时,不会进行虚拟表查找,并且调用给定类型的函数(在本例中为您的类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.

这里,您的operator =()函数不是虚函数,因此使用指针的类型而不是指针指向的类型。

#5


0  

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.

对于使用自己的运算符实现的派生类,运算符必须在基类中是虚拟的,否则将使用基类实现。