简体   繁体   English

重载运算符 == 和多态的好习惯?

[英]Good practice for overloading operator == and polymorphism?

Here is my goal: I have an abstract base class A implementing an operator ==, then I have several derived classes (ie B and C) that each implement an operator ==.这是我的目标:我有一个抽象基类 A 实现了一个运算符 ==,然后我有几个派生类(即 B 和 C),每个类都实现了一个运算符 ==。 I want that when I test b1 == b2 it call the operator defined in B, but I also want to be able to call b1 == c1 and it call the operator defined in the base class A.我希望当我测试 b1 == b2 时它调用 B 中定义的运算符,但我也希望能够调用 b1 == c1 并且它调用基类 A 中定义的运算符。

Indeed, my library represent geometric object and even though b1 and c1 are not the same class they may represent the same 3D object but stored/formulated in a different manner.事实上,我的库代表几何对象,即使 b1 和 c1 不是同一个类,它们也可能代表相同的 3D 对象,但以不同的方式存储/制定。 The operator == in the base class A is slow but test exactly if the 3D objects are equal (by disctretizing) and the operators defined in the child class are faster as they know which formulation is used and can check exactly for equality.基类 A 中的运算符 == 速度较慢,但​​可以准确地测试 3D 对象是否相等(通过离散化),并且子类中定义的运算符速度更快,因为它们知道使用的是哪种公式并且可以准确地检查是否相等。

Here was my first try :这是我的第一次尝试:

// Base class A
class A{

public:
  A() {}

  // ... some pure virtual methods

  virtual bool operator==(const A& other) const {
    std::cout<<" operator == in A"<<std::endl;
    // slow equality test by discretization
  }

  virtual bool operator!=(const A& other) const {
    return !(*this == other);
  }

}; // end A

// Derived class B
class B: public A{

public:
  B() {}

  // ... stuff

  virtual bool operator==(const B& other) const {
    std::cout<<" operator == in B"<<std::endl;
    // fast and exact test between two B objects
  }

  virtual bool operator!=(const B& other) const {
    return !(*this == other);
  }

}; // end B

// Derived classC
class C: public A{

public:
  C() {}

  // ... stuff

  virtual bool operator==(const C& other) const {
    std::cout<<" operator == in C"<<std::endl;
    // fast and exact test between two C objects
  }

  virtual bool operator!=(const C& other) const {
    return !(*this == other);
  }

}; // end C

This implementation worked only for test between the same objects :此实现仅适用于相同对象之间的测试:

B b1(...),b2(...);
C c1(...),c2(...);
b1 == b2; // OK, output " operator == in B"
c1 == c2; // OK, output " operator == in C"
b1 == c1; // do not compile : unknow conversion from C to B

So, to fix this issue I added the following methods in B and C implementation (1) :因此,为了解决这个问题,我在 B 和 C 实现 (1) 中添加了以下方法:

  virtual bool operator==(const A& other) const {
    return A::operator==(other);
  }

  virtual bool operator!=(const A& other) const {
    return !(*this == other);
  }

Now, my first test code work :现在,我的第一个测试代码工作:

b1 == c1; // OK, output " operator == in A" as expected

But, I still cannot use polymorphisme (not 100% sure it's the right term in this context) with this operators :但是,我仍然无法将多态性(在这种情况下不能 100% 确定它是正确的术语)与以下运算符一起使用:

A* a_b1 = new B(...);
A* a_c1 = new C(...);
b1 == *a_b1; // output " operator == in A" !
c1 == *a_c1; // output " operator == in A" !

So to fix this, I changed the method added in (1) to the implementation of B and C try to cast the input of type A to the current child type.所以为了解决这个问题,我将(1)中添加的方法更改为 B 和 C 的实现尝试将类型 A 的输入强制转换为当前子类型。 Here is the final result :这是最终结果:

// Base class A
class A{

public:
  A() {}

  // ... some pure virtual methods

  virtual bool operator==(const A& other) const {
    std::cout<<" operator == in A"<<std::endl;
    // slow equality test by discretization
  }

  virtual bool operator!=(const A& other) const {
    return !(*this == other);
  }

}; // end A

// Derived class B
class B: public A{

public:
  B() {}

  // ... stuff

  virtual bool operator==(const B& other) const {
    std::cout<<" operator == in B"<<std::endl;
    // fast and exact test between two B objects
  }

  virtual bool operator!=(const B& other) const {
    return !(*this == other);
  }

  // CHANGED METHOD :
  virtual bool operator==(const A& other) const {
   const B* other_cast = dynamic_cast<const B*>(&other);
   if(other_cast)
     return *this == *other_cast;
   else
     return A::operator()(other);
  }

  virtual bool operator!=(const A& other) const {
    return !(*this == other);
  }

}; // end B

// Derived classC
class C: public A{

public:
  C() {}

  // ... stuff

  virtual bool operator==(const C& other) const {
    std::cout<<" operator == in C"<<std::endl;
    // fast and exact test between two C objects
  }

  virtual bool operator!=(const C& other) const {
    return !(*this == other);
  }

  // CHANGED METHOD :
  virtual bool operator==(const A& other) const {
   const C* other_cast = dynamic_cast<const C*>(&other);
   if(other_cast)
     return *this == *other_cast;
   else
     return A::operator()(other);
  }

  virtual bool operator!=(const A& other) const {
    return !(*this == other);
  }

}; // end C

So, with this code I achieved what I wanted, ie :所以,通过这段代码,我实现了我想要的,即:

B b1(...),b2(...);
C c1(...),c2(...);
b1 == b2; // OK, output " operator == in B"
c1 == c2; // OK, output " operator == in C"
b1 == c1; // OK, output " operator == in A"
A* a_b1 = new B(...);
A* a_c1 = new C(...);
b1 == *a_b1; //OK, output " operator == in B" !
c1 == *a_c1; //OK, output " operator == in C" !

But I am really not sure if it's a good way to achieve that, as the need for a cast usually highlight a bad design.但我真的不确定这是否是实现这一目标的好方法,因为需要演员阵容通常会突出一个糟糕的设计。 What are your suggestions to improve this code ?您对改进此代码有什么建议?

As a possible way to solve your problem you couldimplement the comparison as a non-member template function, with specialization for the possible and valid combinations.作为解决您的问题的一种可能方法,您可以将比较实现为非成员模板函数,并对可能和有效的组合进行专门化。

Simple (and incomplete) example:简单(且不完整)示例:

// Base case
template<typename T, typename U>
std::enable_if_t<std::is_base_of_v<A, T> && std::is_base_of_v<A, U>, bool> operator==(T const&, U const&);
// The enable_if is to make sure only A and derivatives of it could be used

// Specialization: Compare A against A
template<>
bool operator==(A const& l, A const& r) { /* Some implementation... */ }

// Specialization: Compare B against B
template<>
bool operator==(B const& l, B const& r) { /* Some implementation... */ }

// Specialization: Compare B against A
template<>
bool operator==(B const& l, A const& r) { /* Some implementation... */ }

// Specialization: Compare B against C
template<>
bool operator==(B const& l, C const& r) { /* Some implementation... */ }

// Specialization: Compare C against C
template<>
bool operator==(C const& l, C const& r) { /* Some implementation... */ }

Only those comparisons explicitly specialized will be allowed, any other will lead to build errors.只允许那些明确专门的比较,其他任何比较都会导致构建错误。 And each specialization could be implemented to perform the comparisons in the most effective way.并且可以实施每个专业化以最有效的方式进行比较。

Yes it's a lot of seemingly duplicated code, but the specializations could call some common functions for combinations that are to be compared in the same way (for example comparing a B against C is probably the same as comparing C against B , and thus can be implemented in a shared function).是的,它有很多看似重复的代码,但专业化可以调用一些通用函数来以相同的方式进行比较(例如,比较BC可能与比较CB相同,因此可以是在共享函数中实现)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM