操作符重载
定义:让加减乘除,不局限于整型数的操作,也可以实现类的相加…
实例:
加法重载
class Point
{
private:
int x;
int y;
...
};
Point operator+(Point &p1, Point &p2)
{
cout<<"this is a operator +"<<endl;
Point n;
n.x = p1.x + p2.x;
n.y = p1.y + p2.y;
return n;
}
通过重载,就可以实现类的相加了
有趣的现象
b = a++;
(先执行 b = a,再执行 a = a+1)
b = ++a;
(先执行 a = a + 1,再执行 b = a)
自加的重载实现
class Point
{
private:
int x;
int y;
...
};
/* Point p(1,2); ++p */
Point &operator++(Point &p)
{
cout<<"++p"<<endl;
p.x += 1;
p.y += 1;
return p;
}
/* Point p(1,2); p++ */
Point operator++(Point &p, int a)
{
cout<<"p++"<<endl;
Point n;
n = p
p.x += 1;
p.y += 1;
return n;
}
++p和p++进行重载时函数名一模一样,通过什么来区分?
答:通过传入不同参数来区分
在++p的重载函数和p++的重载函数中的返回值为什么不一样?为什么++p的返回值要以引用的形式出现?
首先在Point类的构造函数和析构函数里面加入打印信息
class Point
{
private:
int x;
int y;
public:
Point()
{
cout<<"Point()"<<endl;
}
Point(int x, int y) : x(x), y(y)
{
cout<<"Point(int x, int y)"<<endl;
printInfo();
}
/* 拷贝构造函数 */
Point(const Point &p)
{
cout<<"Point(const Point &p)"<<endl;
x = p.x;
y = p.y;
}
~Point()
{
cout<<"~Point()"<<endl;
}
...
};
接下来看一下主程序
int main()
{
Point p(1, 2);
cout<<"begin"<<endl;
p++;
cout<<"万能的分隔符"<<endl;
++p;
cout<<"end"<<endl;
return 0;
}
程序运行结果如下
Point(int x, int y)
(1, 2)
begin
p++
Point()
Point(const Point&p)
~Point()
~Point()
万能的分隔符
++p
end
~Point()
下面对运行结果进行逐行分析
1:执行Point p(1, 2)这句时,进入构造函数
2:构造函数Point(int x, int y)里面的打印信息
3:main函数里面的打印信息
4:执行p++时,程序跳转到函数operator++(p++)里面的打印信息
5: operator++(p++) 里面的Point n,新建了一个对象,产生的构造函数里执行的打印信息
6: operator++(p++) 函数里面对象p的生成时调用了拷贝构造函数(拷贝构造函数不在本次讨论过程中),从而打印信息
7,8:依次销毁对象p和对象n,调用了析构函数
9:main函数里万能的分隔符
10:执行++p时,程序跳转到函数operator++(++p) 里面的打印信息
11:main函数里面的打印信息
12:销毁main函数里面一开始创建的对象p时调用析构函数产生的打印信息
根据以上的分析,或许你已经得到了答案
为什么要用引用返回?
当你函数需要返回值时,上述的p++ 是进行值返回,需要依靠拷贝构造函数创建对象,然后返回对象的值,最后把对象销毁。由此可见,在它创建对象的那个过程,白白浪费了资源。上述的++p是进行引用返回,省去了创建新对象的过程,直接通过引用传入对象的地址,从而不会浪费空间资源。
既然引用返回那么好用,为什么p++不使用引用返回?
我们继续对如下代码分析
Point operator++(Point &p, int a)
{
cout<<"p++"<<endl;
Point n;
n = p;
p.x += 1;
p.y += 1;
return n;
}
这里的Point n申请的变量存储在栈空间中,当这个函数结束后就会释放内存。如果这个时候你想使用引用返回,相当于它将这片地址返回给调用它的程序。然而,在函数结束时,这片地址所指向的内存已经释放掉了,如果你采用引用返回,就会出现异常。所以,在这里使用引用返回是不妥的。