比较不同类型的物体被认为是好的设计吗

Is it considered good design to compare objects of different types?

本文关键字:认为是 同类型 比较      更新时间:2023-10-16

你会认为这是糟糕设计的证据吗?

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

例如,如果FooType是测量自epoch以来的秒数的double,而BarType是以UTC为单位提供日期的三个整数(年、月和日)的元组,则像上面这样的比较"有意义"。

你见过这样的类型间比较吗?他们在C++社区中不受欢迎吗?

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

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

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

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

个人愿景和经验

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

如何使用它们

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

什么可能出错

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

算术运算符

除了逻辑之外,我还想展示一个带有算术运算符的内部类型示例。当谈到类型内使用时,算术运算符与逻辑运算符非常相似。

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

结论

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

好的设计表明,您应该只比较具有兼容意义的值。一般来说,类型是一个很好的含义线索,但不是最后一个词,事实上,在许多情况下,同一类型的两个值可能具有不兼容的含义,例如以下两个整数:

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等),这是一个很好的设计。

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

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

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

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

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

因此,正如你所看到的,它不仅仅是提出一个比较标准来填充operator==的正文,或者它是否是一个好的实践,这只是一个开始。平等是如此的基本,渗透到你所有计划的意义中。

相关文章: