a review at operator overloading
定义一个complex类
complex c1 (5, 1);
complex c2 (2);
c2 += c1;
c2 += c1 += c1;
由于我们没有对complex类定义+=操作符,所以这一行会报错。
于是乎我们定义complex类+=的operator overloading
inline complex& complex::operator += (const complex& r) {
return __doapl(this, r);
}
inline complex& __doapl(complex* ths, const complex& r) {
ths->re += r.re;
ths->im += r.im;
return *ths;
}
这两行代码源于标准库,看似简单,实际很复杂
- 为何用inline? 因为当函数短小且不断被多次调用的时候会消耗掉大量的stack,所以要用inline,让编译器把这个函数展开
- 为什么+=内部要设计为调用__doapl(this, r)? 不知道,设计问题,照着做就行了,就是要叠一层
- c2 += c1的具体调用顺序是如何?
- 首先编译器读入c2 += c1,识别出+=是一个二元运算符(注意:不是编译器真的预先知道+=代表了二元,而是它找到了c2是左值,+=在中间,c1是右值,所以认定+=是二元操作符),之后去寻找程序中是否有"complex& aaaaaa" "+=" "complex bbbbbb"这样结构的定义
- 于是接着上文,这两段程序难以理解的地方还有一个this的问题,因为我们这个是包装在complex内的function,假设有不是包装在complex内的function,比如普通加法
inline complex operator+(const complex& x, const complex& y) {
return complex(real(x) + real(y), image(x) + image(y));
}
complex c1, c2, c3;
c2 = c1 + c2;
-
这里产生了个疑惑,为什么同为二元运算符,同为加法,这个函数却有x, y两个参数,而
inline complex& complex::operator += (const complex& r)却只有一个呢??- 这涉及到this指针的问题
-
对于
inline complex& complex::operator += (const complex& r)函数,编译器会将它认为是inline complex& complex::operator += (this, const complex & r)因为它是类的成员函数,所以多了一个this,代表这个类的实例本身,所以c2 += c1,本质上还是两个参数,为什么只写一个参数?因为剩下的那个(隐藏的)参数代表自身。 -
对于上述的+号,执行流程为,识别二元操作符+,去找
-
那么:c1+=c2+=c1如何理解呢???
- 因为它的实现是返回一个complex&,假设返回一个void,c2+=c1是可以运行的,但是c2+=c1这个返回值是void,再加到c1就不行了。那么,为什么返回一个complex&而不是complex呢?因为快
-
问题来了,那为什么
inline complex operator+(const complex& x, const complex& y)不return引用呢?这样不也是快么??因为+=后的返回值,是下一次+=的参数,+=到最后,它的最后返回值同样会赋值一个上文已存的complex,这是合法的。inline complex& operator+(const complex& x, const complex& y)不合法,是因为它返回的complex在函数生命周期销毁后,就不具备&了。 -
有一个例外
inline complex& operator+ (const complex& x) {
return x;
}
这里标准库没写&,但实际上写了也没事,因为x的生命周期是上文给的
但是对于-号这么写就是错的,如下:
inline complex& operator- (const complex& x) {
return complex(-real(x), -image(x));
}
- 还有一个问题:
inline complex conj(const complex &x ) {
return complex(real(x), -image(x));
}
cout << conj(c1) << endl;
cout << conj(c1) << conj(c2) << endl;
如何重载<<? 答案是这样的
#include <iostream>
ostream& operator << (ostream& os, complex& c1) {
return os << "image" << c1.image << "real" << c1.real;
}
- 首先这个无法写成类函数,因为cout是一个ostream对象,标准库写好的,我们只能写成global,然后,按照ostream << complex的结构,我们将第一个参数定义为ostream& os, &为了效率,不能加const注意,因为加了const我们就没有办法写入这个ostream了,然后complex& c1。。。。对于连续输出<<,就是一个执行顺序的问题,从左到右,返回ostream&,(不存在ostream&对象在函数内销毁的问题,所以没必要输出ostream)不赘述。
operator overload知识点太杂,这篇博客还是介绍的蛮全的 https://www.cnblogs.com/linuxAndMcu/p/10395383.html
浙公网安备 33010602011771号