比较不同类型的物体被认为是好的设计吗
Is it considered good design to compare objects of different types?
你会认为这是糟糕设计的证据吗?
//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==
的正文,或者它是否是一个好的实践,这只是一个开始。平等是如此的基本,渗透到你所有计划的意义中。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 当基类是依赖类型时,这是一个缺陷吗
- 为什么rand()的使用被认为是不好的
- 为什么 std::shared_ptr 被认为是"heavy"和"expensive",但 std::array "same perfprmance as plain (c-style) arrays
- 无法将运行时类绑定到 XAML T 必须是 WinRT 类型
- 静态自动 constexpr t = { "red" , "black" , "green" } 是什么类型;派生到?
- 这是什么类型的C++语法,我应该采取什么步骤来理解这一点
- 一个C头文件可以被认为是一个接口吗
- 这在C++是什么类型的错误?
- 如何告诉编译器名称是模板类型名称?
- 为什么const char*和const char[]作为函数参数被认为是等价的
- 是一个被认为是不同类型的班级内部的正向声明
- 正在使用Boost Endian算术类型被认为是好实践
- 为什么返回非引用类型的函数表达式被认为是prvalues而不是xvalues
- Objective-C 为什么 .mm 文件被认为是 int* 类型
- C++被认为是弱类型的吗?为什么?
- C++ 多态函数以 void * 和其他指针类型为参数:是否被认为是模棱两可的
- 比较不同类型的物体被认为是好的设计吗
- 根据编译时常量,使用相同的标识符 #define 或类型定义是否被认为是可接受的做法?
- 你认为是什么让这个C++代码变慢了?(它循环通过ADODB记录集,将COM类型转换为字符串,并填充ostringstre