C++大学基础教程
第10章 运算符重载
北京邮电大学电信工程学院
计算机技术中心
重载运算符可以把C++的运算
符扩展到自定义类型和类类
型的领域中,使代码更直
观、易懂,方便、简洁。
第十八章 运算符重载
10.1 运算符重载的需要
10.2 运算符重载的限制
10.3 重载运算符的语法
10.4 重载++和--运算符
10.5 重载赋值运算符
10.6 重载转换运算符
10.1 运算符重载的需要
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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 运算符重载的语法
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-11-
10.3 运算符重载的语法
两种形式:
1、重载为类的成员函数
函数类型 operator 运算符(形参表)
{
函数体;
}
2、重载为类的友元函数
friend 函数类型 operator 运算符(形参表)
{
函数体;
}
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-16-
说明
1、二元运算符
对象本身 *this就是其中的一个操作数 ,另
一个操作数由形参 给出,通过运算符重载的函
数进行传递;
2、一元运算符
操作数由对象的 this指针给出,就不再需要
形参了。
一般来说,运算结果的类型与操作数的类型一致
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-17-
说明
在重载复数 “+=”运算符时, return语句中
的表达式是 *this,而其他运 算 符 函 数 的 return语
句的表达式是一个临时对象 complex(r-c.r,i-
c.i)。
其实,将 return *this改为返回一个临时对 象
return complex(r,i)结果是一样的,只是建立临
时对象还要调用构造函数。返回 *this对象就不
需要调用构造函数了,执行效率可以提高。
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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;
}
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-21-
说明
重载为友元函数,比 如 “+”,操作数都由形
参给出,通过运算 符重载的函数进行传递。并
且运算结果的类型与操作数的类型一致。
重载运算符的操作中,无论重载为成员 函
数还是友元函数,其 形参多为引用类型 ,目的
是增加可读性,提 高程序的运行效率,因为使
用引用类型,在进 行参数传递的过程中,不需
要复制临时对象。
10.4 重载++和--运算符
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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 重载赋值运算符
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-31-
10.5 重载赋值运算符
默认的赋值运算符
在 C++中系统提供一个默认的重载的赋值
运算符,所以同类的对象可以互相赋值。
缺省=运算符 缺省拷贝构造函数
功能完全相同。
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-32-
10.5 重载赋值运算符
例如:
RMB r1(20.3), r2;
RMB r3=r1;
r2 = r1;
创建对象 r3,调用的是拷贝构造函数, 即
用已有的对象创建新对象。
r2在赋值运算表达式中,对象已经存在 ,
使用 “=”为对象赋值,调用的是赋值运算符。
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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();
}
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-37-
说明
由于在类的构造过程中动态申请了对内
存,因此必须重载拷贝构造函数和赋值运算
符。
1、拷贝构造函数在创建对象时调用,因为
此时对象还不存在 ,只需要申请新的空间,而
不需要释放原有资源空间。
2、赋值运算符在对象已存在的条件下调
用,因此需要先释放原对象占用的空间,然后
申请新的空间。
10.6 重载转换运算符
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-39-
10.6 重载转换运算符
在 C++中,数据类型转换对于基本数据类
型有两种方式:
1、隐式数据类转换
2、显式数据类型转换,也叫强制类型转
换。
对于自定义类型和类类型,类型转换操作
是没有定义的。
强制类型转换使用 “( )”运算符完成,在
C++中我们可以 将 “( )”运算符进行重载,达到
数据转换的目的。
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-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();
}
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-43-
10.6 重载转换运算符
对于 r3=r1+2.40;的系统工作
1、寻找重载的成员函数 +运算符
2、寻找重载的友元函数 +运算符
3、寻找转换运算符
4、验证转换后的类型是否支持 +运算。
转换运算符重载一般建议尽量少使用。
2005-4-28
北京邮电大学电信工程学院计算机技术中心
-44-
小结
1、注意运算符重载的规则和限制
2、重载运算符的时候要注意函数的返回类型
3、前增量和后增量运算符的重载区别
4、赋值运算符重载要注意内存空间的释放和重
新申请。
5、转换运算符重载与构造函数、析构函数一样
没有返回值,通过 转换运算符重载可以在表达
式中使用不同类型 的对象,但要注意转换运算
符重载不可滥用。