根据我教C++的经验,操作员重载是导致学生最悲伤的主题之一.甚至在stackoverflow上查看问题:例如,将+运算符设为外部或成员?如何处理对称性等,似乎很麻烦.
当我从C++迁移到Java时,我担心我会错过这种能力,但除了像[]或()之类的运算符之外,我真的不觉得需要重载运算符.事实上,我觉得没有它们的程序更具可读性.
注意:我把它作为社区维基.我们来讨论一下.我想听听意见.
重载的运算符就像spice.一点可以让事情变得更好; 太多可以让它变得难吃.
每个C++程序员应该知道的一些重载示例,即使他们不同意:
需要operator =()才能使C++对象的行为与值类似.
运算符 - >()是实现智能指针所必需的
operator <<()和operator >>()需要将类型集成到iostream框架中
默认情况下,在比较存储在标准库容器中的对象时,将使用operator <()
operator()()用于实现标准库算法使用的仿函数
如果您实现自己的迭代器,则运算符++()可用
抱怨操作过载很容易,只要它们不以令人惊讶的方式行事,我真的不会看到这个问题.是的,那里有不好的例子(即使在stl中).例如,请参阅auto_ptr的赋值运算符.像一些运算符一样重载&&
,||
并且,
几乎总是会变坏.但在大多数情况下,让运营商做他们做广告的事情并没有真正的问题.
重载operator+
做一些奇怪的事情是不好的做法,但是如果你把一个名为"Add"的方法放到你把对象序列化到磁盘的类中,那就差一点了.
重载操作符可能是做某些事情的极好方法,但是很容易被滥用.
重载<<
和>>
运算符可以很容易地扩展C++的流,包括新类型的流,I/O的新对象,以及两者.重载->
使智能指针几乎成为C++指针的替代品.重载运算符可以使字符串连接运算符成为可能,并构建新的语法数字,就像int
s 一样.拥有它们可以在库中执行需要在其他语言中进行语言级更改的事情.
他们确实有其局限性.没有适合取幂的算子.只有一个乘法运算符,在某些情况下,有多种方法可以乘法(例如,使用3D矢量,至少有点和交叉乘积).的&&
,||
和逗号运营商不能复制其内置的功能,因为他们不能有短路的评估和序列点.
当然,他们可能会被滥用.例如,没有语言要求,算术运算符必须像算术一样工作.我已经看到了可怕的事情,努力想出一个有人认为很直观的SQL符号.在一个编写得很糟糕的C++程序中,不可能知道什么,比如说a = x * y;
,因为它是a.operator=(x.operator*(y));
,或者可能a.operator=(operator*(x, y));
是什么,并且可以编写运算符函数来做任何事情.
Bjarne Stroustrup设计C++的目的是包括有用的功能而不管滥用的可能性,而James Gosling设计Java的意图是排除过度可滥用的功能,即使它们有些有用.我不清楚这些哲学中的任何一个是正确的还是不正确的,但它们是不同的.
Java旨在避免通常需要某些C++功能的情况,例如运算符重载,多重继承和运行时类型推导,因此它们通常不会被遗漏.无论这是好是坏,或者两者都不是我所知道的.
至于教学生,告诉他们不要自己重载操作员(除非在定义的条件下,如仿函数和赋值操作符),而是指出库如何使用重载操作符.我不相信任何C++学生能够做到正确,如果他们能够做到这一点,他们可以并且将自己学习.他们会知道这很棘手,因为你在课堂上禁止它.一些我永远不会相信任何比for
声明更复杂的东西会发现如何重载运算符,并且无论如何都会这样做,但这就是生命.
运算符重载对于很多目的来说非常重要.如果没有重载operator()的能力,就无法创建Functor.在许多情况下,通用编程会成为一个痛苦的对接.如果我写一个数值算法,我依赖于行为相同的值类型,无论它是float,double,std :: complex还是一些自制类型.我依赖于通常定义的算术运算符,所以我不必为内置类型编写单独的重载,而为自定义类型编写另一个重载.
智能指针依赖于能够重新引用解除引用运算符的对象,以便它们可以像指针一样运行.
运算符重载对于使c ++编程具有可承受性非常重要.至于它很复杂,我只是没有看到它.它并不比创建自己的功能复杂,人们通常认为这很容易.如果将其命名为"multiply",则它是一个函数,如果将其命名为"operator*",则它是一个运算符.但是身体中的代码完全相同.
当然,运营商有时会受到滥用.而<<或>>可能是可接受的边界,但它们是如此普遍知道和使用,我认为这是公平的.
但是,如果你问过像C#这样的运算符重载,我很乐意没有它们.它们的实现更加笨拙,它们不适用于泛型,并且它们不能实现C++使用的所有好的和方便的技巧.