(P22)运算符重载:运算符重载 ,成员函数重载 ,非成员函数重载 ,运算符重载规则
文章目录
1.运算符重载
2.成员函数重载
3.重载非成员函数
4.符合重载规则的操作
1.运算符重载
运算符重载允许标准运算符(如运算符)+、—、*、/、<、>等)应用于自定义数据类型的对象
直观自然,可以提高程序的可读性
它反映了C++的可扩展性
运算符重载只是语法上的便利,是另一种调用函数的方式
运算符重载本质上是函数重载
不要滥用重载,因为它只是语法上的方便,所以只有当涉及的代码更容易写,特别是更容易读取时,才有必要重载
2.成员函数重载
成员函数原型格式:
函数类型 operator 运算符(参数表);
1.
成员函数定义的格式:
函数类型 类名::operator 运算符(参数表){
函数体;
}
函数原型的格式:
friend 函数类型 operator 运算符(参数表);
1.
友元函数定义的格式:
friend 函数类型 类名::operator 运算符(参数表){
函数体;
}
eg:实现一个复数类,22cpp\01.cpp
#include "Complex.h"
int main(void)
{
Complex c1(3, 5);
Complex c2(4, 6);
// c1.Add(c2);
// c1.Display();
//若成员函数或者友元函数都有,VS2008会先运行成员函数重载的函数,但是在VC6中,这俩不能共存
//如果以成员函数的方式重载,等价于c1.operator+(c2)
//如果以友元函数的方式重载,等价于operator+(c1+c2),该operator+的作用域是全局的,不是类作用域
Complex c3 = c1 + c2;
c1.Display();
c2.Display();
c3.Display();
}
类声明及定义
22cpp\Complex.h
#ifndef _CONPLEX_H_
#define _CONPLEX_H_
class Complex
{
public:
Complex(int real, int imag);
Complex();
~Complex();
Complex& Add(const Complex& other);
void Display() const;
Complex operator+(const Complex& other);
//友元函数重载,比成员函数重载多一个参数,因为友元函数不是类的成员,它没有隐含一个自身对象(第一个参数)
friend Complex operator+(const Complex& c1, const Complex& c2);
private:
int real_;
int imag_;
};
#endif /* _CONPLEX_H_ */
22cpp\Complex.cpp
#include "Complex.h"
#include <iostream>
using namespace std;
Complex::Complex(int real, int imag) : real_(real), imag_(imag)
{
}
Complex::Complex()
{
}
Complex::~Complex()
{
}
//返回的是自身的引用,所以不会调用拷贝构造函数
Complex& Complex::Add(const Complex& other)
{
real_+=other.real_;
imag_+=other.imag_;
return *this;
}
//运算符重载本质上是函数重载
//Complex c3=c1+2;因为要将返回的对象赋值给c3,返回了一个新的对象,这里c1和c2对象是不发生改变的
//而上面的那个Add会将c1对象发生改变,所以不能返回*this
Complex Complex::operator+(const Complex& other)
{
int r = real_ + other.real_;
int i = imag_ + other.imag_;
return Complex(r, i);
}
Complex operator+(const Complex& c1, const Complex& c2)
{
int r = c1.real_ + c2.real_;
int i = c1.imag_ + c2.imag_;
return Complex(r, i);
}
void Complex::Display() const
{
cout<<real_<<"+"<<imag_<<"i"<<endl;
}
测试:
c1.Add(c2);
c1.Display();
Complex c3 = c1 + c2;
c1.Display();
c2.Display();
c3.Display();
c1与c2都没有发生改变,只有c3变了
操作符合重载规则的操作
重载运算符不允许发明新的运算符。
无法改变操作对象的数量。
在重载运算符之后,其优先级和组合性不会改变。
无法重载的运算符:
一般而言,单目运算符最好重载为类的成员函数;双目运算符最好重载为类的友元函数。
下列双目运算符不能重载为类的友元函数:=、()、[]、->。
=计算符是双目计算符。调用时,类型不匹配,返回时类型不匹配,不直观,会破坏原计算符。
class Test
{
public:
Test& operator=(const Test& other);
private:
int x_;
};
Test t1;
Test t2;
t1=t2;//等价于t1.operator=(t2);
若是写成类的友元函数,Test是类D的派生类的话
class D : public Test
{
friend Test& operator=(Test& t1, const Test& t2);
};
Test& operator=(Test& t1, const Test& t2)
{
t1.x_ = t2.x_;
return t1;
}
D d;
Test t;
D = d//等价于D.operator=(d);会出现类型不匹配,返回时类型也不匹配
类型转换运算符只能以成员函数方式重载
流运算符只能以友元的方式重载