C++ 类多态性和相等运算符

C++ 类多态性和相等运算符,c++,inheritance,polymorphism,equality,C++,Inheritance,Polymorphism,Equality,我正试着把我的头绕在一些我已经想了很长时间的事情上。 假设我有一个类Base class Base { public: virtual ~Base(){} virtual bool operator== ( const Base & rhs ) const; }; 现在,另一个类继承自它。它有两个相等运算符: class A : public Base { public: bool operator== ( const A & rhs ) const;

我正试着把我的头绕在一些我已经想了很长时间的事情上。 假设我有一个类
Base

class Base
{
public:
    virtual ~Base(){}
    virtual bool operator== ( const Base & rhs ) const;
};
现在,另一个类继承自它。它有两个相等运算符:

class A : public Base
{
public:
    bool operator== ( const A & rhs ) const;
    bool operator== ( const Base & rhs ) const;
private:
    int index__;
};
class B : public Base
{
public:
    bool operator== ( const B & rhs ) const;
    bool operator== ( const Base & rhs ) const;
private:
    int index__;
};
还有另一个类,它也是从Base继承的,它也有两个相等运算符:

class A : public Base
{
public:
    bool operator== ( const A & rhs ) const;
    bool operator== ( const Base & rhs ) const;
private:
    int index__;
};
class B : public Base
{
public:
    bool operator== ( const B & rhs ) const;
    bool operator== ( const Base & rhs ) const;
private:
    int index__;
};
这就是我所理解的(不一定正确)。 我只能使用第一个操作符来检查同一类对象是否相等。 然而,我可以使用第二个操作符检查它们是否是相同类型的类,然后检查它们是否相等。 现在,还有另一个类存在,它围绕着基类的指针,而基类是多态类型A或B

class Z
{
public:
    bool operator== ( const Z & rhs ) const;
private:
    std::shared_ptr<Base> ptr__;
};
B类也一样。这似乎不起作用(应用程序挂起时没有任何错误)。 此外,它使用某种默认运算符,还是使用基类运算符?理想情况下,它应该同时使用Base::operator==和compare类类型

但是,如果我想要一个更详细的比较,基于类a或B的成员,比如
index\uuu
,那么我显然必须与每个类交朋友,因为当我尝试这个方法时,它不会编译(当然,除非我添加一个getter或以某种方式使其可见):


有没有一个优雅、简单的解决方案?我是否仅限于向下投射和尝试,或者是否有其他方法来实现我想要的?

一般来说,在层次结构中,应该有一个公共接口,并且在我看来,
操作符==
应该只在
类中使用接口的(虚拟)getter实现。否则,这就像在层次结构中重新定义函数(不使用
virtual
),这几乎总是一个坏主意。因此,您可能需要考虑一下您的设计,拥有多个
操作符==
似乎有点可疑

非常简单的例子:

#include <iostream>

class A
{
    int _x;
public:
    A(int x):_x(x){}
    virtual int getx() const { return _x; } // runtime
    bool operator==(const A& other){return getx() == other.getx();} // one implementation
};

class B: public A
{
    using A::A;
    int getx() const override // Make all B's equal, runtime
    {
        return 0; // so always 0, all B's are equal
    }
};

int main()
{
    A a1(10), a2(20);
    B b1(10), b2(20);
    std::cout << std::boolalpha << (a1==a2) << std::endl; // false
    std::cout << std::boolalpha << (b1==b2) << std::endl; // always true
}
#包括
甲级
{
int_x;
公众:
A(intx):x(x){}
虚拟int getx()常量{return\u x;}//运行时
bool操作符==(const A&other){return getx()==other.getx();}//一个实现
};
B类:公共A
{
使用A::A;
int getx()const override//在运行时使所有B相等
{
返回0;//所以总是0,所有B都相等
}
};
int main()
{
A a1(10)、a2(20);
B b1(10)、b2(20);

std::cout我同意@vsoftco只在基类中实现
操作符==
,并使用NVI惯用语。但是,我会提供一个纯虚拟函数,派生类需要实现该函数来执行相等性检查。这样,基类就不知道或不关心任何派生类的等价性意味着什么四旬斋

代码
“但当我试图运行它时,它只是挂起”-post code.@vsoftco那么,你的意思是只有Base是可比较的,而不是任何派生类?@Alex,一点也不,
操作符==
是继承的,如果getter是
虚拟的
,那么你就可以去了。@Alex,我想说的是层次结构应该通过公共
Base
接口进行比较,oThewise设计不是最好的(imho)。当你谈到继承时,要记住的习惯用法是,
派生的
始终也是一个
。因此原则上,
矩形
不是一个
正方形
,即使你第一次尝试将其作为派生类来编写。非常感谢vsoftcol,我会看看如何使它更好,因为我不高兴h我的当前代码!@Alex没问题,希望有帮助。@Alex我在许多方面同意vsoftco。但是,我提供了一个解决方案,但有一点不同,它不涉及虚拟getter。相反,它使用NVI习惯用法,并将比较逻辑封装在派生类中。这实际上是我一开始希望的。非常聪明,我将看看我是否能用上它,非常感谢。非常感谢,这是迄今为止我见过的最优雅的东西,谢谢!我不确定我是否理解前提条件是如何工作的,但我会用谷歌搜索它!@Alex前提条件只是记录一个必须遵守的要求,以使事情正常工作。这是来电者的责任(即,
Base::operator==
)以确保满足先决条件。这类似于
std::vector::operator[](index)
上的先决条件,其先决条件是
index
不超出范围,否则存在未定义的行为。
#include <iostream>

class A
{
    int _x;
public:
    A(int x):_x(x){}
    virtual int getx() const { return _x; } // runtime
    bool operator==(const A& other){return getx() == other.getx();} // one implementation
};

class B: public A
{
    using A::A;
    int getx() const override // Make all B's equal, runtime
    {
        return 0; // so always 0, all B's are equal
    }
};

int main()
{
    A a1(10), a2(20);
    B b1(10), b2(20);
    std::cout << std::boolalpha << (a1==a2) << std::endl; // false
    std::cout << std::boolalpha << (b1==b2) << std::endl; // always true
}
#include <iostream>
#include <string>
#include <typeinfo>

class Base
{
public:
    virtual ~Base() {}

    bool operator==(const Base& other) const
    {
        // If the derived types are the same then compare them
        return typeid(*this) == typeid(other) && isEqual(other);
    }

private:
    // A pure virtual function derived classes must implement.
    // Furthermore, this function has a precondition that it will only
    // be called when the 'other' is the same type as the instance
    // invoking the function.
    virtual bool isEqual(const Base& other) const = 0;
};

class D1 : public Base
{
public:
    explicit D1(double v = 0.0) : mValue(v) {}
    virtual ~D1() override {}

private:
    virtual bool isEqual(const Base& other) const
    {
        // The cast is safe because of the precondition documented in the
        // base class
        return mValue == static_cast<const D1&>(other).mValue;
    }

private:
    double mValue;
};

class D2 : public Base
{
public:
    explicit D2(std::string v = "") : mValue(v) {}
    virtual ~D2() override {}

private:
    virtual bool isEqual(const Base& other) const
    {
        return mValue == static_cast<const D2&>(other).mValue;
    }

private:
    std::string mValue;
};

class D3 : public Base
{
public:
    explicit D3(int v = 0) : mValue(v) {}
    virtual ~D3() override {}

private:
    virtual bool isEqual(const Base& other) const
    {
        return mValue == static_cast<const D3&>(other).mValue;
    }

private:
    int mValue;
};

int main()
{
    D1 d1a(1.0);
    D1 d1b(2.0);
    D1 d1c(1.0);

    D2 d2a("1");
    D2 d2b("2");
    D2 d2c("1");

    D3 d3a(1);
    D3 d3b(2);
    D3 d3c(1);

    std::cout << "Compare D1 types\n";
    std::cout << std::boolalpha << (d1a == d1b) << "\n";
    std::cout << std::boolalpha << (d1b == d1c) << "\n";
    std::cout << std::boolalpha << (d1a == d1c) << "\n";

    std::cout << "Compare D2 types\n";
    std::cout << std::boolalpha << (d2a == d2b) << "\n";
    std::cout << std::boolalpha << (d2b == d2c) << "\n";
    std::cout << std::boolalpha << (d2a == d2c) << "\n";

    std::cout << "Compare D3 types\n";
    std::cout << std::boolalpha << (d3a == d3b) << "\n";
    std::cout << std::boolalpha << (d3b == d3c) << "\n";
    std::cout << std::boolalpha << (d3a == d3c) << "\n";

    std::cout << "Compare mixed derived types\n";
    std::cout << std::boolalpha << (d1a == d2a) << "\n";
    std::cout << std::boolalpha << (d2a == d3a) << "\n";
    std::cout << std::boolalpha << (d1a == d3a) << "\n";
    std::cout << std::boolalpha << (d1b == d2b) << "\n";
    std::cout << std::boolalpha << (d2b == d3b) << "\n";
    std::cout << std::boolalpha << (d1b == d3b) << "\n";
    std::cout << std::boolalpha << (d1c == d2c) << "\n";
    std::cout << std::boolalpha << (d2c == d3c) << "\n";
    std::cout << std::boolalpha << (d1c == d3c) << "\n";

    return 0;
}
Compare D1 types
false
false
true
Compare D2 types
false
false
true
Compare D3 types
false
false
true
Compare mixed derived types
false
false
false
false
false
false
false
false
false