c++为什么要有运算符重载:
C++有许多内置的数据类型,包括int,char,double等,每一种类型都有许多运算符,例如加+,减,乘,除等。当用户定义了类的对象时,两个对象之间是不能进行这些操作的,比如对象a+b,这样的语句如果没有重载+运算符就会出错。但C++允许用户把这些运算符添加到自已的类中以方便类的对象之间的运算就像内置类型的运算一样方便,比如对象a+b这样就很明白更容易懂,当然也可以在类中定义一个对象间相加的函数,比如a.add(b)调用函数add()以实现两个对象a和b相加,但是这条语句没有比a+b更容易让人理解。于是就有了运算符重载。
下面具体对+号进行运算符重载实例(实现复数相加)(1,2i)+(2,3i)=(3,5i):
第一种情况不用运算符重载实现:
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
void add(Complex &other);
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
void Complex::add(Complex &other) //无返回值的类型
{
this->real = this->real + other.real;//这里的this就是指向调用该函数对象的指针
this->image = this->image + other.image;
//c1.add(c); c1 = c1 + c实现了复数相加
this->show(); //打印输出
}
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c1.add(c); //实现复数相加无返回值
return 0;
}
打印出:
(4,6)
用带返回值的情况:
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex add(Complex &other);
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex Complex::add(Complex &other)//有返回值的类型
{
Complex c;
c.real = this->real + other.real;//这里的this就是指向调用该函数对象的指针
c.image = this->image + other.image;
return c;
}
/* 考虑一下此处为什么不返回引用
* 局部变量不会一直存在如果返回引用局部变量用完即消失引用也就不存在
* 什么情况下用引用当这个对象在调用前和调用后都存在的情况下,在下面会见到这种情况
*/
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1.add(c); //实现复数相加有返回值
c2.show();
return 0;
}
同样打印出:
(4,6)
用上面这两种做法来实现复数相加,虽然实现了,单程序的可读性不强,拿到主程序一看不知道要实现什么功能,所以一般不要这种,下面介绍用运算符重载的办法来实现:
第二种情况用运算符重载实现:
运算符重载实质上就是函数的重载
1、用调用成员函数的方法:
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex operator+(Complex &other);//用成员函数的方法重载运算符+号
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex Complex::operator+(Complex &other)
{
Complex c;
c.real = this->real + other.real;//这里的this就是指向调用该函数对象的指针
c.image = this->image + other.image;
return c;
}
/* 考虑一下此处为什么不返回引用
* 局部变量不会一直存在如果返回引用局部变量用完即消失引用也就不存在
* 什么情况下用引用当这个对象在调用前和调用后都存在的情况下,在下面会见到这种情况
*/
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//本质是 c2 = c1.operator+(c);operator+()是个函数
c2.show();
return 0;
}
同样打印出:
(4,6)
相比前两个程序而言这个程序一看就知道要实现什么,和我们常使用的加法一样。
1、用调用友元函数的方法(只需改动函数):
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
friendComplex operator+(Complex& c1,Complex&c2);//用友元函数的方法重载运算符+号
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex operator+(Complex& c1,Complex&c2)//用友元定义
{
Complex c;
c.real = c1.real + c2.real; //在这里就不能用this指针了,因为友元不是该类的成员函数
c.image = c1.image + c2.image;
return c;
}
/* 考虑一下此处为什么不返回引用
* 局部变量不会一直存在如果返回引用局部变量用完即消失引用也就不存在
* 什么情况下用引用当这个对象在调用前和调用后都存在的情况下,在下面会见到这种情况
*/
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//用友元的本质 c2 = operator(c1,c);
c2.show();
return 0;
}
同样打印出:
(4,6)
什么时候用友元什么时候用成员函数???
一般情况下,一元运算符重载为成员函数,二元运算符重载为友元函数.(个例除外)
上面重载+号就是一个双目运算符应该要用友元。。
下面在重载一个单目运算符如-(负号);
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex& operator-();//用成员函数重载负号
friendComplex operator+(Complex& c1,Complex&c2);//用友元函数的方法重载运算符+号
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex operator+(Complex& c1,Complex&c2)//用友元定义
{
Complex c;
c.real = c1.real + c2.real; //在这里就不能用this指针了,因为友元不是该类的成员函数
c.image = c1.image + c2.image;
return c;
}
/* 考虑一下此处为什么不返回引用
* 局部变量不会一直存在如果返回引用局部变量用完即消失引用也就不存在
* 什么情况下用引用当这个对象在调用前和调用后都存在的情况下,在下面会见到这种情况
*/
Complex& Complex::operator-()//c2一直存在可以考虑返回引用
{
this->real = -this->real;
this->image =-this->image;
return *this;
}
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//用友元的本质 c2 = operator(c1,c);
c2.show();
c2 = -c2; //将c2取负
//本质就是 c2.operator -();
c2.show();
return 0;
}
打印出:
(4,6)
(-4,-6)
紧接着再来重载一个++ -- ++分为前加加和后加加。
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex& operator++(); //前加加
Complex& operator-();//用成员函数重载负号
friendComplex operator+(Complex& c1,Complex&c2);//用友元函数的方法重载运算符+号
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex operator+(Complex& c1,Complex&c2)//用友元定义
{
Complex c;
c.real = c1.real + c2.real; //在这里就不能用this指针了,因为友元不是该类的成员函数
c.image = c1.image + c2.image;
return c;
}
Complex& Complex::operator-()//c2一直存在可以考虑返回引用
{
this->real = -this->real;
this->image =-this->image;
return *this;
}
Complex& Complex::operator++()//前加加
{
this->real++;
this->image++;
return *this;
}
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//用友元的本质 c2 = operator(c1,c);
c2.show();
c2 = -c2; //将c2取负
//本质就是 c2.operator -();
c2.show();
++c2; //前加加就是先加加后使用
c2.show();
return 0;
}
打印出:
(4,6)
(-4,-6)
(-3,-5)
可能你会发现前加加是++而后加加也是++那这两个要怎么区分呢?
c++约定 ++或--运算符重载函数中如果形参为空则为前++。
如果形参增加一个int则为后++ 此时的hint无实际意义,仅作为后置与前置 俗称哑元。
下面看后加加
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex& operator++(); //前加加
Complex operator++(int);//后加加
Complex& operator-();//用成员函数重载负号
friendComplex operator+(Complex& c1,Complex&c2);//用友元函数的方法重载运算符+号
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex operator+(Complex& c1,Complex&c2)//用友元定义
{
Complex c;
c.real = c1.real + c2.real; //在这里就不能用this指针了,因为友元不是该类的成员函数
c.image = c1.image + c2.image;
return c;
}
Complex& Complex::operator-()//c2一直存在可以考虑返回引用
{
this->real = -this->real;
this->image =-this->image;
return *this;
}
Complex& Complex::operator++()//前加加
{
this->real++;
this->image++;
return *this;
}
Complex Complex::operator++(int)//后加加
{
Complex tem(*this);//把原来的值用变量保存起来
this->real++;
this->image++;
return tem;
}
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//用友元的本质 c2 = operator(c1,c);
c2.show();
c2 = -c2; //将c2取负
//本质就是 c2.operator -();
c2.show();
++c2; //前加加就是先加加后使用
c2.show();
Complex cc;
cc = c2++; //后加加是先使用在加加
cc.show(); //使用的值
c2.show(); //加加后的值
return 0;
}
打印出:
(4,6)
(-4,-6)
(-3,-5) //
(-3,-5) // 先使用c2的值正确
(-2,-4)
写到这里应该对运算符重载有一定了解了,下面下点总结:
/*
* 1、系统默认了,赋值运算符重载,如无需深赋值,无需重写
* 2、运算符重载的本质是函数重载
* 格式:
* 函数类型 opertaor@(形参列表)
* {
* 重载处理语句
* }
* 3、c++只能重载现有的运算符,并且在现有的运算符当中有如下不能重载:
* ?:条件运算符
* .成员运算符
* .*成员指针运算符
* ::作用域运算符
* sizeof 类型长度运算符
* 4、重载运算符不要改变语意,不要改变结合,优先级,对象参数的个数
* 5、运算符重载函数不能有默认参数
* 6、运算符重载函数中,必须和一个自定义类一起使用。
*/
/*
* 1、运算符重载函数既可以是成员函数,也可以是友元函数(<< >>只能重载为友元)
* 2、运算符重载函数为成员函数时,比重载为友元函数少一个参数由this引进。
* 3、一般情况下,一元运算符重载为成员函数,二元运算符重载为友元函数.(个例除外)
*
* <<流插入运算符 >>流提取运算符已被系统重载
* ostream& operator<<(ostream &os,自定义类&);
* istream& operator<<(ostream &os,自定义类&);
*
* c++约定 ++或--运算符重载函数中如果形参为空则为前++。
* 如果形参增加一个int则为后++ 此时的hint无实际意义,仅作为后置与前置哑元
*/
虽然系统已经把<<和>>已经重载了,但还是希望能用用插入运算符“<<”来输出用户自己声明的类的对象的信息。
下面就来重载一下”<<”和”>>”符。
这里需要知道的是 我们常用到的cin和cout起始是ostream和istream类的对象,所以我们每次包含头文件时都要加上#include<iostream>就是这个道理。
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex& operator++(); //前加加
Complex operator++(int);//后加加
Complex& operator-();//用成员函数重载负号
friendComplex operator+(Complex& c1,Complex&c2);//用友元函数的方法重载运算符+号
friendostream& operator<<(ostream& os,Complex& c);//用友元函数重载运算符<<
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex operator+(Complex& c1,Complex&c2)//用友元定义
{
Complex c;
c.real = c1.real + c2.real; //在这里就不能用this指针了,因为友元不是该类的成员函数
c.image = c1.image + c2.image;
return c;
}
Complex& Complex::operator-()//c2一直存在可以考虑返回引用
{
this->real = -this->real;
this->image =-this->image;
return *this;
}
Complex& Complex::operator++()//前加加
{
this->real++;
this->image++;
return *this;
}
Complex Complex::operator++(int)//后加加
{
Complex tem(*this);//把原来的值用变量保存起来
this->real++;
this->image++;
return tem;
}
ostream& operator<<(ostream& os,Complex& c)
{
os<<"("<<c.real<<","<<c.image<<")"<<endl;
return os;
}
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//用友元的本质 c2 = operator(c1,c);
c2.show();
c2 = -c2; //将c2取负
//本质就是 c2.operator -();
c2.show();
++c2; //前加加就是先加加后使用
c2.show();
Complex cc;
cc = c2++; //后加加是先使用在加加
// cc.show(); //使用的值
// c2.show(); //加加后的值
//这时我们就可以直接输出对象
cout<<cc<<c2; //输出对象
//本质是就是operator<<(operator<<(cout,c2),c) 这就是有返回值的好处可以连续输出
return 0;
}
同样打印出:
(4,6)
(-4,-6)
(-3,-5)
(-3,-5)
(-2,-4)
这样的输出更直接。。
现在再来重载>>应该就很简单了:
Complex.h里面:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include<iostream>
usingnamespace std;
classComplex
{
public:
Complex(double r = 0,double i = 0);
~Complex();
void show();
Complex& operator++(); //前加加
Complex operator++(int);//后加加
Complex& operator-();//用成员函数重载负号
friendComplex operator+(Complex& c1,Complex&c2);//用友元函数的方法重载运算符+号
friendostream& operator<<(ostream& os,Complex& c);//用友元函数重载运算符<<
friendistream& operator>>(istream& is,Complex& c);//用友元函数重载运算符<<
private:
doublereal;
doubleimage;
};
#endif
在Complex.cpp里面:
#include"Complex.h"
Complex::Complex(double r,double i):real(r),image(i)
{}
Complex::~Complex()
{}
Complex operator+(Complex& c1,Complex&c2)//用友元定义
{
Complex c;
c.real = c1.real + c2.real; //在这里就不能用this指针了,因为友元不是该类的成员函数
c.image = c1.image + c2.image;
return c;
}
Complex& Complex::operator-()//c2一直存在可以考虑返回引用
{
this->real = -this->real;
this->image =-this->image;
return *this;
}
Complex& Complex::operator++()//前加加
{
this->real++;
this->image++;
return *this;
}
Complex Complex::operator++(int)//后加加
{
Complex tem(*this);//把原来的值用变量保存起来
this->real++;
this->image++;
return tem;
}
ostream& operator<<(ostream& os,Complex& c)
{
os<<"("<<c.real<<","<<c.image<<")"<<endl;
return os;
}
istream& operator>>(istream& is,Complex& c)
{
is>>c.real>>c.image;
return is;
}
void Complex::show()
{
cout<<"("<<real<<","<<image<<")"<<endl;
}
在main.cpp里面:
#include<iostream>
usingnamespace std;
#include"Complex.h"
int main()
{
Complex c(1,2);
Complex c1(3,4);
Complex c2;
c2 =c1+c; //实现复数相加有返回值
//用友元的本质 c2 = operator(c1,c);
c2.show();
c2 = -c2; //将c2取负
//本质就是 c2.operator -();
c2.show();
++c2; //前加加就是先加加后使用
c2.show();
Complex cc;
cc = c2++; //后加加是先使用在加加
// cc.show(); //使用的值
// c2.show(); //加加后的值
//这时我们就可以直接输出对象
cout<<cc<<c2; //输出对象
//本质是就是operator<<(operator<<(cout,c2),c) 这就是有返回值的好处可以连续输出
cin>>c2; //输入对象的值
cout<<c2; //输出
return 0;
}
打印:
(4,6)
(-4,-6)
(-3,-5)
(-3,-5)
(-2,-4)
5 6 //输入5 6
(5,6) //打印出 5 6
以上程序都是验证过的,大家可以试一下,相信把这几个程序弄懂了,c++运算符重载也就弄懂的差不多了。