派生类中的 Operator== 永远不会被调用

发布于 2024-08-19 06:14:42 字数 1302 浏览 4 评论 0原文

有人可以让我摆脱这痛苦吗?我试图弄清楚为什么派生运算符==永远不会在循环中被调用。为了简化示例,这是我的基类和派生类:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

泪冰清 2024-08-26 06:14:42

那是因为您尚未将运算符==设为虚拟,因此在运行时不会考虑实际类型。

不幸的是,仅仅将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.

手长情犹 2024-08-26 06:14:42

有两种方法可以解决这个问题。

第一个解决方案。我建议在循环中添加一些额外的类型逻辑,以便您知道何时有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_;
}

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

list<Derived*> coll;

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

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_;
}
咆哮 2024-08-26 06:14:42

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

无风消散 2024-08-26 06:14:42

当成员函数是虚拟的时,虚拟表在运行时用于多态地调用指针实际指向的类型(在本例中为您的类 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.

苏辞 2024-08-26 06:14:42

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文