下面这两种重载!=运算符的方法有什么区别。哪个更好?
Class Test
{
...//
private:
int iTest
public:
BOOL operator==(const &Test test) const;
BOOL operator!=(const &Test test) const;
}
BOOL operator==(const &Test test) const
{
return (iTest == test.iTest);
}
//overload function 1
BOOL Test::operator!=(const &Test test) const
{
return !operator==(test);
}
//overload function 2
BOOL Test::operator!=(const &Test test) const
{
return (iTest != test.iTest);
}
我刚刚看到函数1的语法用于调用兄弟运算符函数,并想知道以这种方式编写它是否会带来任何好处。
答案 0 :(得分:7)
您的第一次重载确保即使您的!=
的实施发生变化,对您的类型调用==
也始终与调用==
相反。
您的第二个重载功能没有,因为可以为==
提供任何实现,并在将来更改现有的实现。
如果你想确保!=
总是与==
相反,那就去第一个(以额外函数调用为代价,无论如何都可以很好地内联)。
这是一个很好的例子。假设您有一个包含字段Point2D
和x
的课程y
。如果您要实施==
,则必须在字段x
和字段y
上进行比较。如果您通过调用!=
来实施operator==
,则代码更短,并且如果您转移到极坐标代码,则会有一个更少的函数更改。
随着类字段的变化,平等测试和比较总是容易受到维护错误的影响。最大限度地减少直接访问状态的方法数量可以降低出错的风险。
答案 1 :(得分:2)
他们几乎肯定会编译成相同的机器代码。
我更喜欢选择2,因为我觉得说“operator ==”很尴尬。但你可以使用
return ! (*this == test)
恕我直言也很清楚易懂。
答案 2 :(得分:2)
我可以想到以这种方式编写它的许多原因(或者可能是同一原因的方面)。它们归结为:DRY。
确保两个对象始终为==
或!=
如果你决定改变课堂上的内容,或者用于平等测试的内容,你只需要在一个地方进行更改
我认为从概念上讲,你真的有两个不同的东西在这里定义:
类Test
一个有用的界面,使用此类的人可以通过该界面确定其实例的相等性
使用方法2,您可以同时执行这两项操作。使用方法1,您在operator==
中定义了相等性,并通过operator!=
提供了接口的其余部分。
有些语言/库更进一步,例如,在Ruby中你可以定义只是 <=>
来比较有序对象和混合Comparable并获得相等,不等式,和between?
。
答案 3 :(得分:1)
版本#1,虽然语法丑陋恕我直言,允许您在一个地方(在==运算符重载)更改相等逻辑。它保证两个重载始终保持同步。
答案 4 :(得分:1)
一般来说,以下声明:
return !(*this == object);
允许您根据一个函数定义!=
。在继承的世界中,子对象只需要定义operator==
以便使用基类operator!=
:
struct Base
{
virtual bool isEqual(const Base& other) const = 0;
bool operator==(const Base& other) const
{
return isEqual(other);
}
bool operator!=(const Base& other) const
{
return !(*this == other); // Uses Base::operator==
}
};
使用上述基类,使用operator!=
定义!=
将需要后代实现更多方法。
此外,!(*this == other)
允许为!=
定义全局通用函数:
template <typename T>
bool operator!=(const T& a, const T& b)
{
return !(a == b);
}
虽然此模式对==
和!=
没有太大帮助,但使用关系运算符时差异较大:<, <=, >, >=
。
答案 5 :(得分:0)
通常,相互实现相关功能总是更好。如果是运营商,总会有团体。例如,!=
可以用==
来实现;后增量可以按预增量实现; >
,<=
和>=
可以<
实施(请参阅std::rel_ops
中的<utility>
)等。如果有关于课程需求的话更改时,您只需要修改核心运算符,其余所有内容都将自动更新以反映新行为。
所有“辅助”运算符的一般实现总是相同的,因此甚至有一个库可以自动提供根据一些提供的运算符定义的运算符。见Boost.Operators
你的例子:
#include <boost/operators.hpp>
class Test : boost::equality_comparable<Test, Test>
{
private:
int iTest;
public:
bool operator==(const Test& test) const;
//look, no operator !=
};
int main()
{
Test a, b;
a != b; //still works
}