6

你会考虑这种不良设计的证据吗?

//FooType and BarType not in the same hierarchy
bool operator==(const FooType &, const BarType &);
bool operator<(const FooType &, const BarType &);

例如,如果FooType测量double自纪元以来的秒数,并且BarType是三个整数(年、月和日)的元组,以 UTC 提供日期,则上述比较“有意义”。

你见过这样的类型间比较吗?他们在 C++ 社区中是不是不被看好?

4

4 回答 4

4

首先,使用自由函数而不是成员函数并没有错,实际上这是推荐的做法。请参阅 Scott Meyer 的非成员函数如何改进封装。不过,您需要提供两个方向的比较:

bool operator==(const FooType &, const BarType &);
bool operator==(const BarType &, const FooType &);

其次,如果比较有意义,提供这些比较是完全可以接受的。例如,标准库允许您将std::complex相等的值与浮点进行比较,但不能小于。

您要避免的一件事是没有意义的比较。在您的示例中,其中一个时间值是双精度值,这意​​味着一旦您考虑到标准促销,就会对任何浮点或整数值进行比较。这可能超出了您的预期,因为无法确定任何特定值是否代表时间。类型检查的丢失意味着有可能出现意外错误。

于 2013-07-08T16:40:06.347 回答
3

个人愿景和经验

我个人并不反对不同类型之间的比较。我什至鼓励它,因为它可以提高代码的可读性;让你正在做的事情看起来更合乎逻辑。除了基本的数字类型,也许是字符串和字符之外,我发现很难给你一个逻辑的类型内比较,而且我不记得遇到过很多。不过,我遇到了很多这样使用的算术运算符。

如何使用它们

你应该小心你正在做的事情,它们很少被使用是有原因的。如果你提供一个比较两种不同类型的函数,结果应该是合乎逻辑的,并且是用户直观的预期。为它编写好的文档也是可取的。Mark Ransom 已经说过了,但是如果用户可以在两个方向上进行比较,那就很好了。如果您认为使用运算符的比较不够清晰,则应考虑使用命名函数。如果您的运算符可以具有多种含义,这也是一个非常好的解决方案。

会出什么问题

您无法完全控制用户将如何处理您所写的内容。tletnes 给出了一个很好的例子,比较两个整数,但结果没有意义。与此相反,两种不同类型的比较可能是非常正确的。浮点数和整数都代表秒,可以很好地进行比较。

算术运算符

在逻辑旁边,我想展示一个带有算术运算符的内部类型示例。在谈论类型内使用时,算术运算符很像逻辑运算符。

假设您有一个运算符 + 用于二维向量和一个正方形。这是做什么的?用户可能认为它会缩放正方形,但另一个用户确信它会平移!这类问题可能会让您的用户感到非常沮丧。你可以通过提供好的文档来解决这个问题,但我个人更喜欢的是专门命名的函数,比如 Translate。

结论

类型内逻辑运算符可能很有用并且可以生成干净的代码,但是错误的使用会使一切变得更加复杂。

于 2013-07-09T14:47:02.367 回答
1

好的设计将表明您应该只比较具有兼容含义的值。通常类型是一个很好的含义线索,但不是硬道理,实际上在很多情况下,相同类型的两个值可能具有不兼容的含义,例如以下两个整数:

int seconds = 3 //seconds
int length = 2; //square inches
if(seconds >= length){
    //what does this mean?
}

在此示例中,我们将长度与秒进行比较,但是两者之间没有有意义的关系。

int test_duration = 3 //minutes
float elapsed_time = 2.5; //seconds
if((test_duration * 60) >= elapsed_time ){
    //tes is done
}

在这个例子中,我们比较了两个不同类型(和单位)的值,但是它们的含义仍然是兼容的(它们都代表时间)所以(假设有充分的理由将两者以这种方式存储(例如,易于使用 API 等) ) 这是一个很好的设计。

于 2013-07-08T16:38:19.997 回答
0

根据 Stepanov 的规则(参见编程元素),相等与复制(构造和赋值)(以及不等式)紧密相关。

因此,如果对象表示相等的值,那么继续,使它们相等可比较,但同时考虑这四个操作(相等、[复制]构造、赋值和不等式)。通过扩展,还可以从不同类型来回转换(转换操作或另一侧的构造)。

它还隐式连接到您可以应用于这些值的任何“常规”函数。Stepanov 将两个值定义为相等,如果应用于它们的任何(常规)函数给出相等的结果。

我还要说,即使您可以比较两个对象相等并相互构造一个对象,如果您可以应用于两者的公共函数集(通用或非通用)不是相关集,或者它们的结果通常会产生不相等的值,那么比较不同类型的对象没有什么价值。最糟糕的是,如果其中一种类型从根本上比另一种具有更多功能怎么办?一个人可以保持反身性吗?

最后是算法复杂度的考虑,如果比较两个对象是O(N^2)或更高(其中N是对象在某种度量上的“大小”),那么可以理解比较没有什么价值对象。(参见 John Lakos 的演讲https://www.youtube.com/watch?v=W3xI1HJUy7Q

因此,正如您所看到的,它不仅仅是提出一个比较标准来填充 的正文operator==,或者这是否是一个好的做法,这只是一个开始。平等是如此基本,以至于渗透到你所有程序的意义中。

于 2020-04-09T19:47:34.827 回答