C++之运算符重载详细讲解(二)



C++之运算符重载详细讲解(二):

上一节主要讲解了C++里运算符重载函数,在看了单目运算符(++)重载的示例后,也许有些朋友会问这样的问题。++自增运算符在C或C++中既可以放在操作数之前,也可以放在操作数之后,但是前置和后置的作用又是完全不同的(q前置运算符:先加1,再赋值;后置运算符:先赋值,再加1)。那么要怎么重载它们,才可以有效的区分开来呢?今天我就来说说C++中是怎么处理前置运算符和后置运算符的重载的。以及介绍一下插入运算符(>>)和提取运算符(<<)的重载。

1.在C++里编译器是根据运算符重载函数参数表里是否插入关键字int来区分前置还是后置运算。比如:

#include “stdafx.h”
#include <iostream>

class TDPoint//三维坐标
{
private:
int x;
int y;
int z;
public:
TDPoint(int x=0,int y=0,int z=0)
{
this->x=x;
this->y=y;
this->z=z;
}
TDPoint operator++();//成员函数重载前置运算符++
TDPoint operator++(int);//成员函数重载后置运算符++
friend TDPoint operator++(TDPoint& point);//友元函数重载前置运算符++
friend TDPoint operator++(TDPoint& point,int);//友元函数重载后置运算符++
void showPoint();
};

TDPoint TDPoint::operator++()
{
++this->x;
++this->y;
++this->z;
return*this;//返回自增后的对象
}

TDPoint TDPoint::operator++(int)
{
TDPoint point(*this);
this->x++;
this->y++;
this->z++;
return point;//返回自增前的对象
}

TDPoint operator++(TDPoint& point)
{
++point.x;
++point.y;
++point.z;
return point;//返回自增后的对象
}

TDPoint operator++(TDPoint& point,int)
{
TDPoint point1(point);
point.x++;
point.y++;
point.z++;
return point1;//返回自增前的对象
}

void TDPoint::showPoint()
{
std::cout<<”(“<<x<<”,”<<y<<”,”<<z<<”)”<<std::endl;
}

int main()
{
TDPoint point(1,1,1);
point.operator++();//或++point
point.showPoint();//前置++运算结果

point=point.operator++(0);//或point=point++
point.showPoint();//后置++运算结果

operator++(point);//或++point;
point.showPoint();//前置++运算结果

point=operator++(point,0);//或point=point++;
point.showPoint();//后置++运算结果

return0;
}

结果:

结果

结果

 

从示例代码里可以清楚的看出,后置运算符重载函数比前置运算符重载函数多了一个int类型的参数,这个参数只是为了区别前置和后置运算符,此外没有任何作用。所以在调用后置运算符重载函数时,int类型的实参可以取任意值。

2.在C++中,操作符”<<”和”>>”被定义为左位移运算符和右位移运算符。由于在iostream头文件中对它们进行了重载,使得它们可以用基本数据的输出和输入。

#include “stdafx.h”
#include <iostream>

int main()
{
int a=10;
std::cout<<”a=”<<a<<std::endl;//运算符”<<”重载后用于输出
a=a>>2;//右移运算符
std::cout<<”右移2位:a=”<<a<<std::endl;

std::cout<<”请输入一个整数a:”;
std::cin>>a;//运算符”>>”重载后用于输入
a=a<<2;//左移运算符
std::cout<<”左移2位:a=”<<a<<std::endl;

return0;
}

结果:

结果示例

结果示例

插入运算符”<<”是双目运算符,左操作数为输出流类ostream的对象,右操作数为系统预定义的基本类型数据。头文件iostrem对其重载的函数原型为ostream& operator<<(ostream& ,类型名);类型名就是指基本类型数据。但如果要输出用户自定义的类型数据的话,就需要重载操作符”<<”,因为该操作符的左操作数一定为ostream类的对象,所以插入运算符”<<”只能是类的友元函数或普通函数,不能是其他类的成员函数。一般定义格式:

ostream& operator<<(ostream& ,自定义类名&);

提取运算符”>>”也是如此,左操作数为istream类的对象,右操作数为基本类型数据。头文件iostrem对其重载的函数原型为istream& operator>>(istream& ,类型名);提取运算符也不能作为其他类的成员函数,可以是友元函数或普通函数。它的一般定义格式为:

istream& operator>>(istream& ,自定义类名&);

我还是用上一节用的Complex类(复数类)来举例:

#include “stdafx.h”
#include <iostream>

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
Complex(double real=0,double imag=0)
{
this->real=real;
this->imag=imag;
}
friend std::ostream&operator<<(std::ostream& o,Complex& com);//友元函数重载提取运算符”<<”
friend std::istream&operator>>(std::istream& i,Complex& com);//友元函数重载插入运算符”>>”
};

std::ostream&operator<<(std::ostream& o,Complex& com)
{
std::cout<<”输入的复数:”;
o<<com.real;
if(com.imag>0)
o<<”+”;
if(com.imag!=0)
o<<com.imag<<”i”<<std::endl;
return o;
}

std::istream&operator>>(std::istream& i,Complex& com)
{
std::cout<<”请输入一个复数:”<<std::endl;
std::cout<<”real(实数):”;
i>>com.real;
std::cout<<”imag(虚数):”;
i>>com.imag;
return i;
}

int main()
{

Complex com;
std::cin>>com;
std::cout<<com;

return0;
}

结果:

c++重载运算符结果示例

c++重载运算符结果示例

 

 

C++运算符重载补充之不同数据间的类型转换

我们在使用重载的运算符时,往往需要在自定义数据类型和系统预定义的数据类型之间进行转换,或者需要在不同的自定义数据类型之间进行转换。今天就来讲讲C++中数据类型的转换。


1.对于系统的预定义基本类型数据,C++提供了两种类型转换方式:隐式类型转换和显式类型转换。

int a=5,sum;
double b=5.55;
sum=a+b;//——-(1)
std::cout<<”隐式转换:a+b=”<<sum<<std::endl;

sum=(int)(a+b);//——-(2)
sum=int(a+b);//——-(3)
std::cout<<”显式转换:a+b=”<<sum<<std::endl;

上述代码中的(1)就是含有隐式类型转换的表达式,在进行”a+b”时,编译系统先将a的值5转换为双精度double,然后和b相加得到10.55,在向整形变量sum赋值时,将10.55转换为整形数10,赋值为变量sum。这种转换是C++编译系统自动完成,不需要用户去干预。而上例中的(2)和(3)中则涉及到了显式类型转换,它们都是把a+b所得结果的值,强制转化为整形数。只是(2)式是C语言中用到的形式:(类型名)表达式,而(3)式是C++中的采用的形式:类型名(表达式);

2.那么对于用户自定义的类类型而言,有该如何去实现它们和其他数据类型之间的转换呢,C++中提供了来那个中方法:(1)通过转换构造函数进行类型转换;(2)通过类型转换函数进行类型转换;

毫无疑问转换构造函数就是构造函数的一种,只不过它拥有类型转换的作用罢了。是否记得在C++之运算重载符(1)中两个复数(sum=com1+com2)相加的实例,现在如果我想要实现sum=com1+5.5,那该怎么办,也许你首先会想到再定义一个关于复数加双精度的运算符重载函数。这样做的确可以。另外我们还可以定义一个转换构造函数来解决上述的问题。我们对Comlex类(复数类)进行这样改造:

#include “stdafx.h”
#include <iostream>

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
Complex(double real,double imag)
{
this->real=real;
this->imag=imag;
}
Complex(double d=0.0)//转换构造函数
{
real=d;//实数取double类型的值
imag=0;//虚数取0
}
Complex operator+(Complex com1);//或friend Complex operator+(Complex com1,Complex com2);
void showComplex();
};

Complex Complex::operator+(Complex com1)
{
return Complex(real+com1.real,imag+com1.imag);
}

void Complex::showComplex()
{
std::cout<<real;
if(imag>0)
std::cout<<”+”;
if(imag!=0)
std::cout<<imag<<”i”<<std::endl;
}

int main()
{

Complex com(10,10),sum;
sum=com+Complex(5.5);//Complex(5.5)把双精度数5.5转换为复数5.5+0i
sum.showComplex();//输出运算结果

return0;
}

结果:

结果

结果

上述代码在执行Complex(5.5)时,调用了转换构造函数,将double类型的5.5转换为无名的Complex类的临时对象(5.5+0i),然后执行两个Complex类(复数类)对象相加的运算符重载函数。所以说一般的转换构造函数的定义形式:

类名(待转换类型)

{

函数体;

}

转换构造函数不仅可以将预定义的数据类型转换为自定义类的对象,也可以将另一个类的对象转换成转换构造函数所在的类的对象。

转换构造函数可以把预定义类型转化为自定义类的对象,但是却不能把类的对象转换为基本数据类型。比如:不能将Complex类(复数类)的对象转换成double类型数据。于是在C++中就用类型转换函数来解决这个问题。定义类型转换函数一般形式:

operator 目标类型()

{

return 目标类型的数据;

}

目标类型是所要转化成的类型名,既可以是预定义及基本类型也可以是自定义类型。类型转换函数的函数名(operator 目标类型)前不能指定返回类型,且没有参数。但在函数体最后一条语句一般为return语句,返回的是目标类型的数据。现在我们对Complex类做类似改造:

#include “stdafx.h”
#include <iostream>

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
Complex(double real,double imag)
{
this->real=real;
this->imag=imag;
}
Complex(double d=0.0)//转换构造函数
{
real=d;//实数取double类型的值
imag=0;//虚数取0
}

Complex operator+(Complex com1);//或friend Complex operator+(Complex com1,Complex com2);
operatordouble();//声明类型转换函数
void showComplex();
};

Complex Complex::operator+(Complex com1)
{
return Complex(real+com1.real,imag+com1.imag);
}

Complex::operatordouble()//定义类型转换函数
{
return real;//返回实数部分
}

void Complex::showComplex()
{
std::cout<<real;
if(imag>0)
std::cout<<”+”;
if(imag!=0)
std::cout<<imag<<”i”<<std::endl;
}

 

int main()
{

Complex com(10,10),sum;
sum=com+Complex(5.5);//Complex(5.5)把双精度数5.5转换为复数5.5+0i
sum.showComplex();//输出运算结果

double total;
total=double(com)+5.5;//double(com)把复数(10+10i)转换为双精度数10.0
std::cout<<”把Complex类对象转化为double类型与5.5相加为:”<<total;

return0;
}

结果:

重载运算结果

重载运算结果

3.最后对类型转换函数做几点补充:(1)类型转换函数只能作为类的成员函数,不能定义为类的友元函数;(2)类型转换函数中必须有return语句,即必须送回目标类型的数据作为函数返回值;(3)一个类可以定义多个类型转换函数,C++编译器会根据函数名来自动调用相应的类型转换函数函数;