C++大学基础教程第 10章 运算符重载北京邮电大学电信工程学院计算机技术中心重载运算符可以把 C++的运算符扩展到自定义类型和类类型的领域中,使代码更直观、
易懂,方便、简洁。
第十八章 运算符重载
10.1 运算符重载的需要
10.2 运算符重载的限制
10.3 重载运算符的语法
10.4 重载 ++和 --运算符
10.5 重载赋值运算符
10.6 重载转换运算符
10.1 运算符重载的需要
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -5-
10.1 运算符重载的需要目的
C++代码更直观,易读,使用更方便。
运算符重载的实质运算符重载的实质是函数重载。 只不过它重载的是类似,+ - * / =“这样的操作符。
例子:
#include <iostream>
using namespace std;
void main()
{
char s1[20]=”Hello”;
char s2[20]=”world”;
char s3[20];
strcpy(s3,s1); //字符串拷贝
cout<<s3<<endl;
strcat(s3,s2); //字符串连接
cout<<s3<<endl;
}
例子:添加运算符重载
#include <string>
#include <iostream>
using namespace std;
void main()
{
string s1="Hello";
string s2="world";
string s3;
s3=s1; //字符串拷贝
cout<<s3<<endl;
s3=s1+s2; //字符串连接
cout<<s3<<endl;
}
10.2 运算符重载的限制
10.2 运算符重载的限制
1、重载运算符时,重载运算符的运算顺序和优先级不变。
2、不能创造新运算符
3、规定不能重载的运算符,
Operator Name
,类属关系运算符
.* 成员指针运算符
:,作用域运算符
,条件运算符
# 编译预处理符号
sizeof() 取数据类型的长度
10.3 运算符重载的语法
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -11-
10.3 运算符重载的语法两种形式,
1、重载为类的成员函数函数类型 operator 运算符(形参表)
{
函数体;
}
2、重载为类的友元函数
friend 函数类型 operator 运算符(形参表)
{
函数体;
}
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -12-
1、重载为类的成员函数
1、一元运算符
++,--等
2、二元运算符
+,-,*,/,%,=,+=,-=
下面我们以复数 Complex类为例,实现运算符的重载。
class complex
{
public:
complex(double real=0,double imag=0):
r(real),i(imag){}
complex operator +(complex&);
complex operator -(complex&);
complex operator +=(complex&);
void print()
{
cout<<setiosflags(ios::showpos)
<<r<<" "<<i<<'i'<<endl;
}
private:
double r,i;
};
complex complex::operator +(complex& c)
{
return complex(r+c.r,i+c.i);
}
complex complex::operator -(complex& c)
{
return complex(r-c.r,i-c.i);
}
complex complex::operator +=(complex& c)
{
r+=c.r;
i+=c.i;
return *this;
} 返回自己本身
void main()
{
complex c1(1,1),c2(3,3),c3;
c3=c1+c2; //复数相加
c3.print();
c3=c1-c2; //复数相减
c3.print();
c3+=c2+=c1; //复数相加后赋值
c3.print();
} +4 +4i
- 2 -2i
+2 +2i
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -16-
说明
1,二元运算符对象本身 *this就是其中的一个操作数,另一个操作数由形参给出,通过运算符重载的函数进行传递;
2,一元运算符操作数由对象的 this指针给出,就不再需要形参了 。
一般来说,运算结果的类型与操作数的类型一致
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -17-
说明在重载复数,+=”运算符时,return语句中的表达式是 *this,而其他运算符函数的 return语句的表达式是一个临时对象 complex(r-c.r,i-c.i)。
其实,将 return *this改为返回一个临时对象
return complex(r,i)结果是一样的,只是建立临时对象还要调用构造函数 。 返回 *this对象就不需要调用构造函数了,执行效率可以提高 。
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -18-
2、重载为类的友元函数运算符也可以重载为友元函数,这时运算所需要的操作数都需要通过形参来传递,形参从左到右的顺序就是运算符操作数的顺序。
我们还以 Complex类为例,查看如何将 +,-、
+=重载为友元函数
class complex
{
public:
complex(double real=0,double imag=0):
r(real),i(imag){}
friend complex operator+(complex&,complex&);
friend complex operator -(complex&,complex&);
friend complex& operator +=(complex&,complex&);
void print()
{
cout<<setiosflags(ios::showpos)
<<r<<" "<<i<<'i'<<endl;
}
private:
double r,i;
};
complex operator +(complex& c1,complex& c2)
{
return complex(c1.r+c2.r,c1.i+c2.i);
}
complex operator -(complex& c1,complex& c2)
{
return complex(c1.r-c2.r,c1.i-c2.i);
}
complex& operator +=(complex& c1,complex& c2)
{
c1.r+=c2.r;
c1.i+=c2.i;
return c1;
}
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -21-
说明重载为友元函数,比如,+”,操作数都由形参给出,通过运算符重载的函数进行传递 。
并且运算结果的类型与操作数的类型一致 。
重载运算符的操作中,无论重载为成员函数还是友元函数,其 形参多为引用类型,目的是增加可读性,提高程序的运行效率,因为使用引用类型,在进行参数传递的过程中,不需要复制临时对象 。
10.4 重载 ++和 --运算符
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -23-
10.4 重载 ++和 --运算符在 C++中有一类特殊的运算符,,++”、
,--”运算符,这类运算符是一元运算符,它的运算规律因操作数的位置不同而不同 。
++x,前置自增算符,先自身增 1,再将增加后的值作为表达式的值返回;
x++,后置自增算符,先将本身的值作为表达式的值返回,自身再增 1。
我们以 weight为例,实现如何重载 ++运算符 。
class weight
{
public:
weight(int v=0):value(v) {}
//前置自增
weight& operator ++();
//后置自增
weight operator ++(int);
void print()
{
cout<<value<<endl;
}
private:
int value;
};
//前增量
weight& weight::operator ++()
{
value++;
return *this;
}
//后增量
weight weight::operator ++(int)
{
weight temp(*this); //操作数保存为临时对象
value++; //操作数加 1
return temp; //返回没有加 1的临时对象
}
void main()
{
weight s1(1);
s1++.print();
s1.print();
(++s1).print();
}
1
2
3
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -27-
说明因为重载函数只能从形式参数上加以区别 。
1,前置自增运算符用成员函数实现时,没有形式参数 。
2,后置自增运算符另外增加一个形式上的形式参数,类型定为
int。 这个参数只是用来区别两种自增算符,并不参加实际的运算 。
2、重载为类的友元函数
class weight
{
public:
weight(int v=0):value(v){}
friend weight& operator ++(weight&);
friend weight operator ++(weight&,int);
void print()
{
cout<<value<<endl;
}
private:
int value;
};
weight& operator ++(weight& s)
{
s.value++;
return s;
}
weight operator ++(weight& s,int)
{
weight temp(s);
s.value++;
return temp;
}
10.5 重载赋值运算符
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -31-
10.5 重载赋值运算符默认的赋值运算符在 C++中系统提供一个默认的重载的赋值运算符,所以同类的对象可以互相赋值。
缺省=运算符 缺省 拷贝构造函数功能完全相同。
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -32-
10.5 重载赋值运算符例如:
RMB r1(20.3),r2;
RMB r3=r1;
r2 = r1;
创建对象 r3,调用的是拷贝构造函数,即用已有的对象创建新对象 。
r2在赋值运算表达式中,对象已经存在,
使用,=”为对象赋值,调用的是赋值运算符 。
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -33-
10.5 重载赋值运算符一般来说,这个重载的赋值运算符可以直接使用,不需要自己定义。但是,在有些情况下,比如动态申请对内存的情况,则还是需要自己定义重载的赋值运算符。
下面,以一个例子说明,如何重载赋值运算符。
class Name
{
public:
Name(char *str=NULL);
Name(Name &s);
Name& operator = (Name&);
~Name()
{
delete pName;
}
void print()
{
cout<<pName<<endl;
}
private:
char *pName;
};
Name::Name(char *str) {
if(str==NULL)
pName = NULL;
else{
pName=new char[strlen(str)+1];
strcpy(pName,str);
}
}
Name& Name::operator = (Name& s)
{
delete pName;
pName=new char[strlen(s.pName)+1];
strcpy(pName,s.pName);
return *this;
}
Name::Name(Name &s)
{
pName=new char[strlen(s.pName)+1];
strcpy(pName,s.pName);
}
void main()
{
Name s1("test = operator"),s2;
s2=s1;
s2.print();
}
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -37-
说明由于在类的构造过程中动态申请了对内存,
因此必须重载拷贝构造函数和赋值运算符。
1,拷贝构造函数在创建对象时调用,因为此时对象还不存在,只需要申请新的空间,而不需要释放原有资源空间 。
2、赋值运算符在对象已存在的条件下调用,
因此需要先释放原对象占用的空间,然后申请新的空间。
10.6 重载转换运算符
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -39-
10.6 重载转换运算符在 C++中,数据类型转换对于基本数据类型有两种方式:
1,隐式数据类转换
2,显式数据类型转换,也叫强制类型转换 。
对于自定义类型和类类型,类型转换操作是没有定义的 。
强制类型转换使用,( )”运算符完成,在
C++中我们可以将,( )”运算符进行重载,达到数据转换的目的 。
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -40-
10.6 重载转换运算符转换运算符声明形式
operator 类型名 () ;
特点
1、没有返回值
2、功能类似强制转换我们以 RMB类为例说明如何重载转换运算符
class RMB
{
public:
RMB(double value=0.0)
{
yuan =value;
fen = (value-yuan)*100+0.5;
}
void ShowRMB()
{
cout<<yuan<<,元,
<<fen<< "分 " <<endl;
}
operator double ()
{
return yuan+fen/100.0;
}
private:
int yuan,fen;
};
void main()
{
RMB r1(1.01),r2(2.20);
RMB r3;
//显式转换类型
r3 = RMB((double)r1+(double)r2);
r3.ShowRMB();
//自动转换类型
r3=r1+2.40;
r3.ShowRMB();
//自动转换类型
r3 =2.0-r1;
r3.ShowRMB();
}
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -43-
10.6 重载转换运算符对于 r3=r1+2.40;的系统工作
1、寻找重载的成员函数 +运算符
2,寻找重载的友元函数 +运算符
3,寻找转换运算符
4、验证转换后的类型是否支持 +运算。
转换运算符重载一般建议尽量少使用。
2009-7-29 北京邮电大学电信工程学院计算机技术中心 -44-
小结
1,注意运算符重载的规则和限制
2,重载运算符的时候要注意函数的返回类型
3,前增量和后增量运算符的重载区别
4,赋值运算符重载要注意内存空间的释放和重新申请 。
5,转换运算符重载与构造函数,析构函数一样没有返回值,通过转换运算符重载可以在表达式中使用不同类型的对象,但要注意转换运算符重载不可滥用 。