【问题标题】:how to test for equality between objects with common superclass如何测试具有公共超类的对象之间的相等性
【发布时间】:2020-10-04 22:01:04
【问题描述】:

我有一个名为 X 的虚拟类和子类 X1 X2X3

澄清:这些类是哑数据:intdoublestringvector<> 前面的。可能有指向只读静态数据结构的指针,其中相等是指针是否相等的浅检查。不会有例如FILE*,您可以通过多种方式确定打开的文件是否相等。

我有两个 X* 类型的指针,它们实际上指向子类。

检查相等性的最简单方法是什么?

只是为了表明我已经投入了一些工作,我的计划是:给X一个虚拟方法IsEqual(),它需要一个X* pxThat。每个子类都实现这个方法。该方法将使用dynamic_cast<> 来查看参数是否是它自己的类,如果不是则报告false。否则它将使用动态转换参数逐个字段检查相等性。

不过,我想知道是否有更简单的方法可以做到这一点?

【问题讨论】:

  • operator== 已经存在时,不要去发明自己的名字。动态转换不应该是相关的,因为除非您使用模板函数,否则不会提供任何“坏”作为参数。
  • IsEqual的定义是什么?同一个例子?相同的数据成员?你真的应该发布一些代码。
  • @tadman 我可以让 operator== 虚拟吗?不知道那个。或者如果我不能,它会如何工作?
  • @tadman 如果我不使用dynamic_cast<>,那么我有一个指向基类的指针。在这种情况下,我如何将其与this 进行比较?
  • @tadman thx,添加了内容说明

标签: c++ polymorphism


【解决方案1】:

在 C++ 中,虚方法通常是公共的。

有些 C++ 程序在基类公共方法不是虚拟的情况下使用的一种习惯用法,它用于调用私有虚拟方法。这种方法的基本原理是它将面向公众的 API 与派生类可扩展性 API(虚拟)分开,而不是让面向公众的 API 和派生类 API 纠缠和混合。它被称为non-virtual interface idiom

在我看来,对于您给定的问题,这是一个利用非虚拟界面习语的好地方。因为它使非虚拟的X::operator== 实现更干净,而虚拟的isEqual 更干净、更简单,否则它可能会变得非常复杂。

isEqual() 仅由operator== 调用,并且仅当该运算符确定类匹配时。由于这是有保证的,子类中的isEqual() 实现最好用static_cast 完成,比dynamic_cast 稍快。

#include <typeinfo>
#include <cassert>

namespace {

struct X {
    virtual ~X() = default;
    bool operator==(X const&) const;
private:
    // Allow objects of superclass X to be compared, and supply a
    // working method for subclasses who have no additional fields to
    // check to establish equality.
    virtual bool isEqual(X const& rhs) const { return true; };
};

class X1 : public X {
    int a;
    bool isEqual(X const&) const override;
public:
    X1() : a{} {}
    X1(int a_) : a{a_} {}
};

struct X2 : X { };

struct X3 : X { };

bool X::operator==(X const& rhs) const {
    return typeid(*this) == typeid(rhs) && isEqual(rhs);
}

bool X1::isEqual(X const& rhs) const {
    // isEqual MUST only be called if lhs and rhs are the same type.
    auto const& r = static_cast<X1 const&>(rhs);
    return a == r.a;
}

} // namespace anon



int main() {
    X x;
    X1 x1{7};
    X2 x2;
    X3 x3;

    assert(x == X{});
    assert(x1 != X{});
    assert(x2 != X{});
    assert(x3 != X{});
    assert(x1 == X1{7});
    assert(x2 == X2{});
    assert(x3 == X3{});
    assert(x1 != X2{});
    assert(x2 != X3{});
    assert(x3 != X1{});
    assert(x1 != X1{6});
}

【讨论】:

  • 我不想编辑超过最低限度,但我认为拥有基类普通方法和虚拟方法的好论据是一部分工作(类型相等检查)可以分解出来。每当您在多个实现之间有一些共同点时,如果很容易做到这一点,那么将其考虑在内是有意义的,在这种情况下它是微不足道的。
  • 我认为编辑意味着这取决于 C++20 或更高版本。我使用了 C++17。不过没关系。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
相关资源
最近更新 更多