我可以将operator ==虚拟化以实现平等吗?

问题描述

从这个implementing operator== when using inheritance问题开始,我看到人们说operator==不应设为virtual(公认的答案甚至说“操作员不能是虚拟的” ,后来发现这是不正确的):

c ++允许操作员是虚拟的。但我不会将它们虚拟化。 多态和运算符实际上并不能很好地融合在一起(并且 自由的运算符功能显然根本不是虚拟的)。 ---- Johannes Schaub-小家伙

-1。使Person :: operator ==虚拟是不够的:必须重写Employee :: operator ==才能具有相同的签名。 而且,这仍然会导致道格拉斯指出的问题,即 比较操作的不对称,很奇怪。 ----卢·图拉(Luc Touraille)

我不明白为什么我不能做operator== virtual。我编写了这段代码,似乎可以很好地与多态性配合使用:

#include <iostream>
#include <typeinfo>
using namespace std;

struct Base {
    int b1 = 1;
    int b2 = 2;
    virtual bool operator==(const Base& rhs) const {
        cout << "Base" << endl;
        if (typeid(*this) != typeid(rhs)) {
            cout << "false" << endl;
            return false;
        }
        else {
            cout << "true" << endl;
            return (b1 == rhs.b1) && (b2 == rhs.b2);
        }
    }
};

struct Derived : public Base {
    int d1 = 3;
    int d2 = 4;
    virtual bool operator==(const Base& rhs) const override {
        cout << "Derived" << endl;
        if (typeid(*this) != typeid(rhs)) {
            cout << "false" << endl;
            return false;
        }
        else {
            cout << "true" << endl;
            const Derived& rrhs = static_cast<const Derived&>(rhs);
            return (b1 == rrhs.b1) && (b2 == rrhs.b2) && (d1 == rrhs.d1)
                && (d2 == rrhs.d2);
        }
    }
};

int main()
{
    Derived d;
    Base b1,b2;
    Base *bptr1,*bptr2,*bptr3;
    bptr1 = &b1;
    bptr2 = &d;
    bptr3 = &b2;
    
    if (*bptr2 == *bptr1) {
        cout << "1" << endl;
    }
    else {
        cout << "0" << endl;
    }

    if (*bptr3 == *bptr1) {
        cout << "1" << endl;
    }
    else {
        cout << "0" << endl;
    }

    if ((d == b1) != (b1 == d)) {
        cout << "xxx";
    }
    return 0;
}
@H_404_25@

我的代码有问题吗?

解决方法

通过使用typeidstatic_cast可以解决对称性问题(a == b应该给出与b == a相同的结果)。是的,您的代码行为良好。我加入了行

if (!(*bptr2 == *bptr1) && (*bptr1 == *bptr1)){
    std::cout << "Oops";
}
if (*bptr3 == *bptr1 && !(*bptr1 == *bptr3)){
    std::cout << "Oops";
}

通过额外的测试。因此,您根本没有真正使用多态。您几乎消除了多态性的影响。

,

这是您想要在程序中使用的语义的问题。

在您链接的问题中,OP具有PersonEmployee类。在他们的实现中,您可以使一个人Bob既有一个Person对象(pBob)也有一个Employee对象(eBob)表示,那么情况:

pBob == eBob -> trueeBob == pBob -> false

这是您引用的警告所警告的不对称比较。我相信,这会让大多数人感到惊讶-因此是非常不受欢迎的代码。

如果您添加更多类:ContractorExecutiveSalariedHourlyWorker,这个问题也会变得很陌生。现在,如果您有两个Employee&,则必须调查基础对象类型是什么,并且可能会跳过箍以正确的方式进行比较:Bob是一名承包商,但现在被录用了薪水,怎么办您将contractorBobsalariedBob对象与Employee比较运算符进行比较,以发现当您所有的人都是虚拟比较运算符时,它们实际上是同一位员工/个人吗?

另一方面,可能是您在一个不对称比较运算符很明显的领域工作。

最后,它取决于您希望类的语义是什么,以及如何最好地实现对您有意义的语义。

,

无法定义在多态类层次结构中工作的通用比较运算符。这是几个例子。

示例一。我们正在建立算术层次结构。在BigNumber上操作,基础框架将选择正确的表示形式。

class BigNumber { ... };
class BigInteger : public Number { ... };
class BigRational : public Number { ... };
class BigFloating : public Number { ... };

如果我们遵循这样的哲学,即不同动态类型的两个对象永远不相等,则BigInteger(0)不等于BigRational(0,1)BigFloating(0.0)。这破坏了我们所知道的算法。

示例二。我们正在建立几何层次结构。

class Shape { ... };
class Triangle : public Shape { ... };
class Rectangle : public Shape { ... };

到目前为止一切顺利。 Triangle永远不会等于Rectangle,对吧?让我们添加颜色。

class ColouredTriangle : public Triangle { ... };

糟糕!现在,我们的小型CAD程序已停止工作,因为我们用Triangle替换了ColouredTriangle中的一个Triangle,即使几何引擎对颜色一无所知,只对几何属性感兴趣。更糟糕的是,即使我们将所有ColouredTriangle替换为{{1}},并且如果我们希望几何引擎完全像以前一样工作,所有颜色也必须相同。

也许在某些应用程序域中,首先比较类型ID是一种比较对象的可靠方法,但是我还没有看到。

这与您的编程语言无关。