在Google C++ Style Guide中,section on Operator Overloading建议不要重载任何运算符(“罕见的特殊情况除外”)。具体来说,它建议:
特别是,不要超负荷
operator==
或operator<
就这样 你的班级可以作为一个关键 STL容器;相反,你应该 创建平等和比较仿函数 声明容器时的类型。
我对这样的仿函数看起来有点模糊,但我的主要问题是,为什么你想为此编写自己的仿函数?不会定义operator<
,并且使用标准std::less<T>
函数会更简单吗?使用一个优于另一个是否有任何优势?
答案 0 :(得分:16)
除了更基本的类型之外,小于操作并不总是微不足道,甚至平等可能因情况而异。
想象一下航空公司想要为所有乘客分配登机号码的情况。这个数字反映了登机顺序(当然)。现在,是谁决定谁来谁?您可以采取客户注册的顺序 - 在这种情况下,小于操作将比较登记时间。您可能还会考虑客户为其机票支付的价格 - 低于现在比较机票价格的价格。
......等等。总而言之,在operator <
课程中定义Passenger
是没有意义的,尽管可能需要将乘客安排在已排序的容器中。我认为这就是谷歌所警告的。
答案 1 :(得分:6)
通常,定义operator<
会更好更简单。
您需要使用仿函数的情况是需要多种方法来比较特定类型。例如:
class Person;
struct CompareByHeight {
bool operator()(const Person &a, const Person &b);
};
struct CompareByWeight {
bool operator()(const Person &a, const Person &b);
};
在这种情况下,可能没有一种好的“默认”方式来比较和排序人,因此不定义operator<
并使用仿函数可能会更好。您也可以说通常人们按高度排序,因此operator<
只调用CompareByHeight
,任何需要按权重排序的人都必须明确使用CompareByWeight
。
通常,问题在于定义函子是由类的用户决定的,因此每当需要在有序容器中使用类时,您往往会对同一事物进行许多重新定义。
答案 2 :(得分:5)
嗯,根据您引用的网页,对于仿函数来说没有多少优势(“[运营商]可以欺骗我们的直觉,认为昂贵的操作是廉价的内置操作。”)
我的感觉是,你应该努力让你尽可能地让你成为一流的物品,对我来说,这意味着要让他们理解尽可能多的操作员。
我写了一个仿函数已经有一段时间了,但它看起来像这样:
class MyClass {....}
class LessThanMyClass : std:binary_function<MyClass, MyClass, bool>
{
public bool operator()(MyClass lhs, MyClass rhs)
{ return /* determine if lhs < rhs */ ; }
}
vector<MyClass> objs;
std::sort(objs.begin(), objs.end(), LessThanMyClass());
}
答案 3 :(得分:3)
我可能不会像谷歌风格指南那样。
我认为他们得到的是当你重载operator<
和operator==
时,你正在决定每种类型的使用,而算子类型只适用于那个集合。
如果您需要比较器的唯一方法是将项目放入集合中,那么最好具有专门针对该上下文的函数,而不是适用于所有上下文的运算符。
您可能希望按时间顺序对采购订单进行排序,但一般来说,将它们与总价格进行比较是有意义的。如果我们重载operator<
来比较日期以便我们可以将它们加载到集合中,那么我们就会引入另一个客户可能滥用我们认为比较总价格的operator<
的风险。
答案 4 :(得分:3)
我认为背后的信息没有定义运算符&lt;是排序是集合的属性,而不是对象的属性。相同对象的不同集合可以具有不同的排序。因此,在指定集合的类型而不是运算符&lt;。
时,应使用单独的函子在实践中,很多类可能都有自然顺序,这是应用程序中集合中使用的唯一顺序。在其他情况下,订购甚至可能与应用程序无关,只与集合相关,因此它可以在以后查找项目。在这些情况下,定义运算符&lt;。
非常有意义请记住,当我们设计对象模型时,我们只是为现实世界的一个子集建模。在现实世界中,可能有多种不同的方法来对同一类的对象进行排名,但在我们工作的应用程序域中,可能存在一个相关的对象。
如果代码演变为需要与第一个相关的第二个排序,则应该重构该类以删除运算符&lt;并将两个排名函数放在单独的仿函数中。这表明没有一个排名比其他排名更重要的意图。
关于算术运算符,除非要实现算术类型,否则不应重载它们。
当然,每条规则都有例外。如果你不知道你是否应该例外,你可能不应该。经验将成为您的指导。
答案 5 :(得分:2)
仿函数是一个operator ()
的类。在这种情况下,该方法将采用被比较类型的两个参数,如果第一个小于第二个,则返回bool
结果。
编辑:要建立James Curran所说的内容,您可以在课程中定义您的仿函数。所以,例如:
class MyClass
{
struct LessThan : public std::binary_function<MyClass, MyClass, bool>
{
bool operator()(const MyClass & first, const MyClass & second) const
{
return first.key < second.key;
}
};
};
答案 6 :(得分:1)
具有讽刺意味的是,仿函数还需要覆盖一个运算符(函数调用运算符 - operator ()
),所以我不确定它们的意义。