运算符重载
来源:互联网 发布:长春java 编辑:程序博客网 时间:2024/05/18 03:24
接触C++只有3个月,只是写给自己看的啦 0 0.
OOP 第二次读书报告
1)你可以重载运算符为成员函数和非成员函数,应该选择哪个?
2)重载运算符为成员函数和非成员函数的特点?
3)如何理解“逐个成员赋值memberwise assignment”(与“逐个字符赋值bitwise assignment”相对应)?
1)
·单目运算符最好重载为类的成员函数,双目运算符最好重载为类的非成员函数:
const complex operator +(const complex &r,const complex &s);//双目运算符重载为非成员函数(全局函数)friend const complex operator +(const complx &r,const complex &s);//双目运算符重载为非成员函数(友元函数) const complex operator -()const;//单目运算符重载为成员函数
例外:
不要重载为非成员函数
当然,单目运算符也可以重载为类的非成员函数,双目运算符也可以重载为类的成员函数:
const complex operator +(const complex &x)const;//双目运算符重载为成员函数const complex operator -(const complex &x);//单目运算符重载为非成员函数(全局函数)friend const complex operator -(const complex &x); //单目运算符重载为成员函数(友元函数)
·如果第一个运算符不是该类的一个对象,而是其它类的对象或者普通变量等,那么不能使用重载为成员函数,因为重载为成员函数有一个隐藏的this指针,第一个参数默认为该类的对象:
const complex operator +(int r,const complex &s);//第一个参数不是此类的对象,重载为非成员函数(全局函数)friend const complex operator -(int r,const complex &s);//第一个参数不是此类的对象,重载为非成员函数(友元函数)
·考虑不同参数顺序,使用友元非成员函数:
friend const complex operator -(const complex &r,int s);friend const complex operator -(int r,const complex &s);
·如果运算操作需要修改运算数自身,那么最好使用成员函数:
const Integer& operator++();//前缀运算符
·操作数希望存在隐式类型转化,使用非成员函数:
const Integer operator +(const Integer &r,const Integer &s);Integer x(3),y(7),z;z = x + y;//okz = x +3;//okz = 3 + y;//okz = 3 + 7;//ok
如果使用成员函数:
const Integer operator +(const Integer &x)const;Integer x(3),y(7),z;z = x + y; //okz = x + 3; //okz = 3 + y; //error
对于z = x + 3,编译器用构造函数把3构造成int对象。
对于z = 3 + y, 编译器从左到右读取,看到3的时候就确定用整数的加减,再发现右边的不是整数,所以需要把对象变成整数的手段,但是对象里没有这个手段。
· 类型转换函数定义为成员函数:
operator int();
2)
成员函数:
有一个隐藏的参数,this指针。对于一元运算符,不需要参数;对于二元运算符,只需要that参数,以此类推。
这样也就限制了第一个参数必须为类的对象,对于整数类,z = 3 + y 就是错误的。
complex x(1,2), y(3,5), z;z = x + y;//等价于x.operator+(y)
其中左边的算子决定使用哪个重载的+。
非成员函数:
不存在隐藏的this指针,需要把所有运算符按照顺序传入。
在开发类时使用非成员函数进行运算符重载,一般将其设置为友元函数。
在已有类上,如果有办法接触到其成员,也就可以在不修改的前提下利用非成员函数添加运算符重载,对第一个参数的限制也就降低。但是在一定程度上也破坏了C++的封装性。
complex x(1,2), y(3,5), z;z = x + y;//等价于operator+(x,y)
3)
当你去调一个参数是对象本身的函数时,在这个时候,就会发生拷贝构造。
但是在写这种拷贝构造函数的时候,传参数的时候却应该传入对象的引用,如果这里传的不是引用而是对象本身,那么在函数接收参数的时候(入栈过程),会有产生一个临时对象来接收这个参数,这个过程又是一次拷贝构造,因此函数反复调用自己,形成死循环。所以必须传入引用。
如果定义了自己拷贝构造函数:
<span style="font-family:宋体;font-size: 10.5pt;"> complex::complex(const complex &x); </span>
那么在执行下述代码时:
complex b(1,2);complex a = b;//等价于complex a(b);
就会调用上面自己的拷贝构造函数。
这就叫做memberwise copy.
如果你没有写那个自定义的拷贝构造函数,系统会为你提供一个拷贝构造函数。发生的过程是先用b的构造函数去构造一个b对象,然后再按字节复制给a对象。(直接将一段内存上的数据拷贝到另一段内存上,类似于memcpy)
这就叫做bitwise copy.
按字节拷贝存在这些问题:
1.对于指针直接拷贝,导致两个指针指向同一块内存,这样如果我们同时调用它们,就会让同一块内存析构两次。我们所希望的是拷贝后的指针指向新的那块内存。
2.如果拷贝构造函数内部还存在其它对象,那么就会继续调用拷贝构造函数,不断递归,但是对于按字节拷贝来说,就没有这种操作方式。
如果你没有将其写成初始化形式,而是写成了赋值形式:
complex b(1,2);complex a;a = b;
在读到complex a这一行时,没有接收到任何参数,调用的是a的缺省构造函数,下一行a = b调用的将是自己的赋值重载函数。
如果没有自己的赋值重载函数,将发生bitwise copy.
以下是一个测试代码:
#include<iostream>using namespace std;class complex{int r;int i;public:complex& operator =(const complex &x){cout<<"complex& operator ="<<endl;if(this!=&x){this->r = x.r; this->i = x.i;}return *this;}friend ostream& operator <<(ostream& out, const complex &x){out<<x.r<<" + "<<x.i<<"i"<<endl;}complex(int x,int y):r(x),i(y) { cout<<"common constructor"<<endl; };complex(){ cout<<"default constructor"<<endl; };complex(const complex &x){cout<<"copy constructor"<<endl;if(this!=&x){this->r = x.r;this->i = x.i;}}};int main(){complex b(1,2);cout<<"b = "<<b;complex a = b;cout<<"a = "<<a;complex c;c = b;cout<<"c = "<<c;}
运行结果:
先发生b的普通构造,再是a的拷贝构造,最后是c的缺省构造与赋值。
注释掉拷贝构造函数:
不发生拷贝构造,但a依旧得到了值。
注释掉赋值的重载:
不发生重载,但c依旧得到了值。
- 运算符重载 [++,--,+,<<; &&,||(不可重载)]
- 重载之运算符重载
- 重载赋值运算符
- C++运算符重载
- 运算符重载
- 运算符重载总结
- 运算符重载例子
- 运算符重载
- 运算符重载
- 基础:运算符重载
- 运算符重载
- 运算符重载
- 重载赋值运算符
- C#运算符重载
- C++-运算符重载
- 重载赋值运算符
- 运算符重载
- 有关运算符重载
- 【php】foreach中使用引用引起的问题
- android开发经验总结
- iOS开发39-Mac OS X下搭建XAMPP环境
- 日志
- Unity3D让物体从规定时间内移动到某一位置
- 运算符重载
- install logicalDoc
- 杭电2031进制转换
- format函数
- C++中map容器的说明和使用技巧
- hdu3280
- mac pro 配置caffe记录
- QuickSort
- c++primer第五版第八章练习