关于C++中运算符重载的豆知识

就是总结一下运算符重载的一些细微小技巧,目前一共六条

今日程老师的课刚好提到运算符重载,正好小小应景一下

主要内容来源是《Effective C++》和《More Effective C++》这两本书

================================================================

一、继承“=”时的小陷阱

对父类重载了“=”运算符,子类却没有继承过来!

究其原因,竟是系统自动生成的拷贝赋值函数(即对“=”的重载),覆盖了父类的同名函数

想原汁原味地继承对“=”的重载目前也找不到什么好方法

当然其他的运算符重载无论是继承还是virtual,都遵守普通成员函数的规则

 

二、重载“=”时请返回引用

因为有连等的情况出现,例如:

a=b=c=d=5,实际上是a=(b=(c=(d=5)))

所以至少要有返回值。那返回对象还是返回对象引用呢?当然是return *this的形式返回引用了!

不然的话,每次都要生成临时变量,进行构造、析构,电脑都觉得累~

顺便说一下,同理要返回引用的还有[]、+=系列、前置的++等。

从返回引用与返回对象的效率对比上,还可以推出另一个好用技巧:

无论什么函数,当函数的参数是较复杂的变量时(比如你自定义的某个类对象),将函数的参数类型改为const & 同样可以提高效率!道理一样是节省构造、析构,前面的const还能保证调入者方面的安心,并保留了值传递时不改动原有对象的特性

最后在重载“=”时别忘了处理自身赋值的情况,比如a=a这样的,把拷贝构造新对象放在析构旧对象的语句之前就好了

 

三、重载“()”的妙用:传说中的函数对象(伪函数)

是的,“()”也可以重载,比如:

Class Sum{

    int operator ()(int value1, int value2){

        return (value1+value2);

    }

}

然后Sum sum;cout<<sum(2,3)就可以看到5了,调用起来和函数指针一模一样

但是具备了几个函数指针不具备的特征:

1.方便实现inline

inline是在编译期的动作,像函数指针这种运行时的行为不太容易做到inline,但是在以成员函数的方式声明的函数对象想inline还是很容易的。

在VC下,可能会发现qsort比sort还慢,难道那个q不是quick的意思?!

其实是因为qsort使用了函数指针,sort使用了伪函数,因而在内联优化上后者会胜出

2.更多的辅助存储,干掉全局变量!

因为是以成员方法的形式调用的,即是说这个对象的其他成员属性可以拿来做辅助存储,代替了全局变量的作用

3.可以加virtual关键字实现多态

 

运算符重载的本质是静态链接,而virtual则会导致动态链接,于是这二者在此结合于一身了

 

四、前置的++与后置的++

1.不同的参数以进行重载函数的区分

二者都是单目运算符,但是运算符重载时需要用不同参数进行区分,后置的要给一个int参数

前置的++:type& operator ++(){...};

后置的++:const type operator ++(int){...};

2.前置++请返回引用

道理同上文提到的“=”重载,同样这也能允许++++i 这样的写法

3.后置++请返回const对象

后置++返回对象应该没什么争议,因为在返回时,原对象的值已经改变了。想要达到“原对象自增一,返回自增前的值”只能返回一个新对象了。

为什么要加const呢?因为如果不这样的话,i++++ 这样的写法过后,先不管能不能编译通过,就算能通过,i只是自增了1次而非两次

因为返回值是新对象,所以链式调用里第二次自增的不是i 而是刚刚产生的新对象

既然无论如何达不到目的,干脆就以编译器报错的方式告诉用户不能这么写好了

4.后置++的实现请调用前置++

因为在 “对原对象自增1” 的操作上,二者是完全一致的,所以后置++就直接调用前置++好了

5.后置++比前置++慢

因为要多生成新对象所以慢。只想要自增效果的话就调用前置++好了,我也没把握编译器会不会帮你把孤零零的后置++优化为前置++

 

五、基础四则运算也有小技巧!

这回轮到加减乘除了

小技巧就是请返回const对象

这样做的好处是,当你把if (a*b==c)误写成了if (a*b=c)的时候,编译器会显式地指出你这个错误

另外由于运算得到了新值,所以要生成新对象,不能返回引用。

当然如果你写成了a=a+5,不妨改为a+=5: “+=” 的操作符返回的是引用,效率更高

 

六、重载&&、||前请三思

&&和||有着非常好用的短路特性

比如说if (p!=null && strlen(p)>8)这种写法,你完全不必担心strlen取了一个空的p,因为p为空的话在p!=null后就会立刻跳转了,不会执行第二个逻辑判断条件

但是如果要重载&&和||的话,这个短路特性就要丢失

因为重载的本质就是函数,函数调用的时候,无论如何你也无法阻止编译器把传递的参数一个个计算好然后压进栈,更糟糕的是你还可能无法控制在入栈之前各参数计算的顺序。

同理还有逗号运算符,逗号运算符是从左向右依次执行的,重载后这个特性也将丢失

================================================================

其实还有更多技巧未能总结过来,比如说隐式转换对运算符重载带来的危害、operator new和new operator的区别等等,有兴趣的童鞋可以自行翻阅相关书籍

一条评论

发表评论

电子邮件地址不会被公开。

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>