《C程序设计运算符重载资料》由会员分享,可在线阅读,更多相关《C程序设计运算符重载资料(51页珍藏版)》请在金锄头文库上搜索。
1、C-C-程序设计运算符重载程序设计运算符重载资料资料4.1 运算符重载的概念运算符重载的概念运算符重载的概念运算符重载的概念C+语言允许重新定义已有的语言允许重新定义已有的运算符运算符,使其,使其完成一些只在该完成一些只在该特定类特定类中使用的中使用的特定操作特定操作,这就是这就是运算符重载运算符重载如用加法如用加法“”运算符进行两个复数的相加。运算符进行两个复数的相加。若有若有z1=2+3i,z2=4-8i,在数学中,可直接,在数学中,可直接用用“”实现实现z3=z1z2,也就是将,也就是将z1和和z2的的实部和虚部分别相加,实部和虚部分别相加,z3=2+4+(3-8)i=6-5i。这时必须
2、实现复数相加。比如用户可以通这时必须实现复数相加。比如用户可以通过定义一个函数来实现复数相加过定义一个函数来实现复数相加例例4.1 通过函数实现复数相加示例。通过函数实现复数相加示例。/ 声明复数数声明复数数class Complexprivate:/ 数据成员数据成员double real;/ 实部实部double image;/ 虚部虚部public:/ 公有函数公有函数Complex(double r = 0, double i = 0): real(r), image(i) / 构造函数构造函数void Show() const;/ 输出复数输出复数static Complex Add
3、(const Complex &z1, const Complex &z2);/ 复数加法复数加法;void Complex:Show() const/ 输出复数输出复数if (image 0) cout real image i endl;/ 虚部为负虚部为负else if (image = 0) cout real endl;/ 虚部为虚部为0else cout real “+” image “i” endl;/ 虚部为负虚部为负例例4.1 通过函数实现复数相加示例。通过函数实现复数相加示例。Complex Complex:Add(const Complex &z1,const Compl
4、ex &z2) Complex z(z1.real + z2.real, z1.image + z2.image);/ 定义复数对象定义复数对象return z;/ 返回复数返回复数int main()/ 主函数主函数main()Complex z1(2, 3), z2(6, -5), z3; / 定义复数对象定义复数对象z1.Show();/ 输出输出z1z2.Show();/ 输出输出z2z3 = Complex:Add(z1, z2);/ z3=z1+z2z3.Show();/ 输出输出z3system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回
5、值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:2+3i6-5i8-2i请按任意键继续请按任意键继续. . .在在Add()函数体中的两行代码可以用函数体中的两行代码可以用“return Complex(z1.real + z2.real, z1.image + z2.image);”代代替,替,“Complex(z1.real + z2.real, z1.image + z2.image)”的含义是建立一个的含义是建立一个临时复数对象临时复数对象,它的实部,它的实部为为z1.real + z2.real,虚部为,虚部为z1.image + z2.image,在
6、,在建立临时对象的过程中调用了构造函数,语句建立临时对象的过程中调用了构造函数,语句return将将此临时对象作为函数的返回值。此临时对象作为函数的返回值。 运算符重载运算符重载能否像能否像实数实数的的加法加法运算一样,直接用加号运算一样,直接用加号“+”来实现来实现复数运算呢?例如在程序中直接用复数运算呢?例如在程序中直接用“z3=z1+z2”进行运进行运算,这需要对运算符算,这需要对运算符“+”进行进行重载重载。运算符重载的方法在实质上就是定义一个运算符重载的方法在实质上就是定义一个重载运算符重载运算符的函数的函数,在执行被重载的运算符时,系统将调用此,在执行被重载的运算符时,系统将调用此
7、函函数实现相应的运算数实现相应的运算。运算符重载本质就是。运算符重载本质就是函数的重载函数的重载。重载运算符的函数的原型如下:重载运算符的函数的原型如下:返回值类型返回值类型operator运算符运算符(形参表形参表);例如将例如将“”用于用于Complex类的加法运算运算符重载的类的加法运算运算符重载的函数原型可以为:函数原型可以为:Complex operator+(const Complex &z1, const Complex &z2);例例4.2 通过运算符重载实现复数相加的示例。通过运算符重载实现复数相加的示例。#include / 编译预处理命令编译预处理命令using name
8、space std;/ 使用命名空间使用命名空间std / 声明复数数声明复数数class Complexprivate:/ 数据成员数据成员double real;/ 实部实部double image;/ 虚部虚部public:/ 公有函数公有函数Complex(double r = 0, double i = 0): real(r), image(i)/ 构造函数构造函数void Show() const;/ 输出复数输出复数friend Complex operator+(const Complex &z1,const Complex &z2) return Complex(z1.rea
9、l + z2.real, z1.image + z2.image); ;void Complex:Show() const/ 输出复数输出复数if (image 0) cout real image i endl;/ 虚部为负虚部为负else if (image = 0) cout real endl;/ 虚部为虚部为0else cout real + image i endl;/ 虚部为负虚部为负上面的程序在上面的程序在Visual C+ 2005,Visual C+ 2005 Express,Dev-C+和和MinGW Developer Studio都能正常运行,但都能正常运行,但在在V
10、isual C+ 6.0下会出现的编译时错语,是下会出现的编译时错语,是Visual C+ 6.0的一个的一个Bug,在,在Visual C+ 6.0中可将:中可将:#include / 编译预处理命令编译预处理命令using namespace std;/ 使用命名空间使用命名空间std 改为:改为:#include / 编译预处理命令编译预处理命令#include / 包含包含system()的声明的声明 例例4.2 通过运算符重载实现复数相加的示例。通过运算符重载实现复数相加的示例。/ int operator+(int a, int b) return a + b; / 错错,重载运算
11、符的函数的参数不能全部是重载运算符的函数的参数不能全部是C+的标准类型的标准类型int main()/ 主函数主函数main()Complex z1(2, 3), z2(6, -5), z3; / 定义复数对象定义复数对象z1.Show();/ 输出输出z1z2.Show();/ 输出输出z2z3 = z1 + z2;/ 进行复数加法运算进行复数加法运算z3.Show();/ 输出输出z3system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:2+3i6-5i8-2i请按任
12、意键继续请按任意键继续. . .4.2 运算符重载方式运算符重载方式运算符重载方式运算符重载方式 C+的运算符按参加运算的操作数个数可分为的运算符按参加运算的操作数个数可分为单目运单目运算符算符、双目运算符双目运算符、三目运算符三目运算符以及以及不确定目数运算不确定目数运算符符单目运算符只有一个操作数,例如单目运算符只有一个操作数,例如!p(取反运算符),(取反运算符),-b(负号运算符)等(负号运算符)等双目运算符有两个操作数参与运算,例如双目运算符有两个操作数参与运算,例如2+3(加法运算符)(加法运算符),a=b(赋值运运算符)等(赋值运运算符)等三目运算符有三个操作数参与运算,三目运算
13、符只包括问号三目运算符有三个操作数参与运算,三目运算符只包括问号运算符,行例如运算符,行例如z?x:y不确定目数运算符是操作数个数不确定,可根据需要重载为不确定目数运算符是操作数个数不确定,可根据需要重载为不同的操作数个数,不确定目数运算符只包括函数调用运算不同的操作数个数,不确定目数运算符只包括函数调用运算符符“()()”在在C+中只能重载中只能重载单目运算符单目运算符、双目运算符双目运算符及及不确定不确定目数运算符目数运算符“()”4.2.1 运算符重载为类的成员函数运算符重载为类的成员函数通过该类的通过该类的对象对象来调用来调用运算符函数运算符函数,由于,由于对象对象本身将作为本身将作为
14、一一个操作数个操作数,因此要求第一个操作数的,因此要求第一个操作数的类型类型为为用户自定义类用户自定义类,参数表中的参数表中的参数个数参数个数比操作数个数比操作数个数少一少一。下面是运算符重载为类的成员函数的一般形式:下面是运算符重载为类的成员函数的一般形式:class 类名类名private:/ 数据成员数据成员public:/ 公有函数公有函数返回值类型返回值类型 operator运算符运算符(形参表形参表);/ 运算符重载为类的成员函数运算符重载为类的成员函数;其中其中“operator运算符运算符”是运算符函数的是运算符函数的专用函数名专用函数名。用类的成员函数重载单目运算符用类的成员
15、函数重载单目运算符单目运算符单目运算符的运算符在一般情况下重载为类的成员函数时,的运算符在一般情况下重载为类的成员函数时,形参表为形参表为空,空,以当前对象(即调用该以当前对象(即调用该运算符函数运算符函数的对象)作为运算符的对象)作为运算符唯一的操唯一的操作数作数。http:/ 例例4.3 单目运算符重载为类的成员函数示例。单目运算符重载为类的成员函数示例。/ 声明整型类声明整型类class Integerprivate:/ 数据成员数据成员int num;/ 数据值数据值public:/ 公有函数公有函数Integer(int n = 0): num(n) / 构造函数构造函数void S
16、et(int n) num = n; / 设置数据值设置数据值int Get() const return num; / 返回数据值返回数据值Integer operator-() const return Integer(-num); / 重载负号运算符重载负号运算符“-”;int main()/ 主函数主函数main()Integer i;/ 定义整型对象定义整型对象i.Set(6);/ 设置数据值设置数据值cout i.Get() endl;/ 输出数据值输出数据值6i = -i;/ 对对i进行求负号运算进行求负号运算, -i等价于等价于i.operator-();cout i.Get(
17、) num + a.num); ;int main()/ 主函数主函数main()Integer i(6), j(9), k;/ 定义整型对象定义整型对象k = i + j;/ 对整型对象求加法运算,对整型对象求加法运算,i+j等价于等价于i.operator+(j); couti.Get()+j.Get()=k.Get()endl;/ 输出数值输出数值system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:6+9=15请按任意键继续请按任意键继续. . .4.2.2 运算
18、符重载为类的友元函数运算符重载为类的友元函数可以像将可以像将运算符运算符重载为类的重载为类的友元函数友元函数,这时参数表中的,这时参数表中的参数个数参数个数与与操作数个操作数个相等,并且操作数的相等,并且操作数的第一个操作数第一个操作数的类型的类型不要求是用不要求是用户自定义类户自定义类。下面是运算符重载为类的友元函数的一般形式:下面是运算符重载为类的友元函数的一般形式:class 类名类名private:/ 数据成员数据成员public:/ 公有函数公有函数friend 返回值类型返回值类型 operator运算符运算符(形参表形参表);/ 运算符重载为类的友元函数运算符重载为类的友元函数;
19、由于是由于是友元函数友元函数,因此在函数原型前应加上关键字,因此在函数原型前应加上关键字friend。用类的友元函数重载单目运算符用类的友元函数重载单目运算符将将单目运算符单目运算符重载为类的友元函数时,重载为类的友元函数时,友友元函数形参表元函数形参表中有中有一个参数一个参数作为该运算符作为该运算符的的操作数操作数。 例例4.5 单目运算符重载为类的友元函数示例。单目运算符重载为类的友元函数示例。#include / 编译预处理命令编译预处理命令using namespace std;/ 使用命名空间使用命名空间std / 声明整型类声明整型类class Integerprivate:/ 数
20、据成员数据成员int num;/ 数据值数据值public:/ 公有函数公有函数Integer(int n = 0): num(n) / 构造函数构造函数void Set(int n) num = n; / 设置数据值设置数据值int Get() const return num; / 返回数据值返回数据值friend Integer operator-(const Integer &a)/ 重载负号运算符重载负号运算符- return Integer(-a.num); ;在在Visual C+ 6.0下会出现的编译时错语,是下会出现的编译时错语,是Visual C+ 6.0的一个的一个Bug
21、,在,在Visual C+ 6.0中可将:中可将:#include / 编译预处理命令编译预处理命令using namespace std;/ 使用命名空间使用命名空间std 改为:改为:#include / 编译预处理命令编译预处理命令#include / 包含包含system()的声明的声明 例例4.5 单目运算符重载为类的友元函数示例。单目运算符重载为类的友元函数示例。int main()/ 主函数主函数main()Integer i;/ 定义整型对象定义整型对象i.Set(6);/ 设置数据值设置数据值cout i.Get() endl;/ 输出数据值输出数据值i = -i;/ 对对i
22、进行求负号运算进行求负号运算, -i等价于等价于operator-(i);cout i.Get() endl;/ 输出数据值输出数据值system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:6-6请按任意键继续请按任意键继续. . .用类的友元函数重载双目运算符用类的友元函数重载双目运算符将将双目运算符双目运算符重载为类的重载为类的友元函数友元函数时,友时,友元函数形参表中包含有元函数形参表中包含有两个参数两个参数,这两个,这两个参数分别作为运算符的参数分别作为运算符的左左
23、、右操作数右操作数。 例例4.6 双目运算符重载为类的友元函数示例。双目运算符重载为类的友元函数示例。#include / 编译预处理命令编译预处理命令using namespace std;/ 使用命名空间使用命名空间std / 声明整型类声明整型类class Integerprivate:/ 数据成员数据成员int num;/ 数据值数据值public:/ 公有函数公有函数Integer(int n = 0): num(n) / 构造函数构造函数void Set(int n) num = n; / 设置数据值设置数据值int Get() const return num; / 返回数据值返
24、回数据值friend Integer operator+(const Integer &a, const Integer &b) return Integer(a.num + b.num); / 重载重载+,两个操作数都是对象两个操作数都是对象friend Integer operator+(int a, const Integer &b) return Integer(a + b.num); / 重载重载+,第一操作数是标准类型第一操作数是标准类型friend Integer operator+(const Integer & a, int b) return Integer(a.num +
25、 b); / 重载重载+,第二操作数是标准类型第二操作数是标准类型;在在Visual C+ 6.0下会出现的编译时错语,是下会出现的编译时错语,是Visual C+ 6.0的一个的一个Bug,在,在Visual C+ 6.0中可将:中可将:#include / 编译预处理命令编译预处理命令using namespace std;/ 使用命名空间使用命名空间std 改为:改为:#include / 编译预处理命令编译预处理命令#include / 包含包含system()的声明的声明 例例4.6 双目运算符重载为类的友元函数示例。双目运算符重载为类的友元函数示例。int main()/ 主函数主
26、函数main()Integer i(6), j(9), k;/ 定义整型对象定义整型对象k = i + j;/ i+j等价于等价于operator+(i,j),两个操作数都是对象两个操作数都是对象 cout i.Get() + j.Get() = k.Get() endl;k = 1 + j;/ 1+j等价于等价于operator+(1,j),第一操作数是标准类型第一操作数是标准类型cout 1 + j.Get() = k.Get() endl;/ 输出数值输出数值k = i + 2;/ i+2等价于等价于operator+(i,2),第二操作数是标准类型第二操作数是标准类型cout i.Ge
27、t() + 2 = k.Get() endl;/ 输出数值输出数值system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:6+9=151+9=106+2=8请按任意键继续请按任意键继续. . .4.2.3 运算符重载为普通函数运算符重载为普通函数可以将运算符重载为可以将运算符重载为普通函数普通函数,这时参数,这时参数表中的表中的参数个数参数个数与与操作数个相等操作数个相等,并且第,并且第一个操作数一个操作数的的类型类型不要求是不要求是用户自定义类用户自定义类。下面是运算符重
28、载为普通函数的一般形式:下面是运算符重载为普通函数的一般形式:返回值类型返回值类型 operator运算符运算符(形参表形参表);由于是普通函数,因此在函数原型前不应由于是普通函数,因此在函数原型前不应加上关键字加上关键字friend。用普通函数重载单目运算符用普通函数重载单目运算符将将单目运算符单目运算符重载为重载为普通函数普通函数时,函数形时,函数形参表中有参表中有一个参数一个参数作为该运算符的作为该运算符的操作数操作数。 例例4.7 单目运算符重载为类的普通函数示例。单目运算符重载为类的普通函数示例。/ 声明整型类声明整型类class Integerprivate:/ 数据成员数据成员i
29、nt num;/ 数据值数据值public:/ 公有函数公有函数Integer(int n = 0): num(n) / 构造函数构造函数void Set(int n) num = n; / 设置数据值设置数据值int Get() const return num; / 返回数据值返回数据值;Integer operator-(const Integer &a)/ 重载负号运算符重载负号运算符- return Integer(-a.Get(); ;int main()/ 主函数主函数main()Integer i;/ 定义整型对象定义整型对象i.Set(6);/ 设置数据值设置数据值cout
30、i.Get() endl;/ 输出数据值输出数据值6i = -i;/ 对对i进行求负号运算进行求负号运算, -i等价于等价于operator-(i);cout i.Get() endl;/ 输出数据值输出数据值-6system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统用普通函数重载重载双目运算符用普通函数重载重载双目运算符将双目将双目运算符重载运算符重载为为普通函数普通函数时,函数形时,函数形参表中包含有参表中包含有两个参数两个参数,这两个参数分别,这两个参数分别作为运算符的作为运算符的左左、右操作数右操作数。 例例4
31、.8 双目运算符重载为普通函数示例。双目运算符重载为普通函数示例。/ 声明整型类声明整型类class Integerprivate:/ 数据成员数据成员int num;/ 数据值数据值public:/ 公有函数公有函数Integer(int n = 0): num(n) / 构造函数构造函数void Set(int n) num = n; / 设置数据值设置数据值int Get() const return num; / 返回数据值返回数据值;Integer operator+(const Integer &a, const Integer &b) / 重载运算符重载运算符+ return I
32、nteger(a.Get() + b.Get(); int main()/ 主函数主函数main()Integer i(6), j(9), k;/ 定义整型对象定义整型对象k = i + j;/ 对整型对象求加法运算,对整型对象求加法运算,i+j等价于等价于operator+(i,j)cout i.Get() + j.Get() = k.Get() endl;system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:6+9=15请按任意键继续请按任意键继续. . .运算符重载
33、运算符重载一般地讲,一般地讲,单目运算符单目运算符最好重载为类的最好重载为类的成成员函数员函数,双目运算符双目运算符最好重载为类的最好重载为类的友元友元函数函数或或普通函数普通函数。*4.3 典型运算符重载典型运算符重载 *4.3.1 重载赋值运算符重载赋值运算符“=” 由于由于赋值运算符赋值运算符重载后实现将一个重载后实现将一个表达式的值表达式的值赋值给用户赋值给用户自定义对象自定义对象,也就是赋值运算符的,也就是赋值运算符的第一个操作数第一个操作数是类型为是类型为用户自定义类用户自定义类的对象,因此的对象,因此C+规定赋值运算符规定赋值运算符“=”只能只能重载为类的重载为类的成员函数成员函
34、数,一般重载格式为:,一般重载格式为:类名类名 类名类名:operator=(const 类名类名 &源对象源对象)if (this != &源对象源对象) / 目的对象与源对象不是同一个对象目的对象与源对象不是同一个对象/ 复制被被赋值对象复制被被赋值对象return *this;/ 返回目的对象返回目的对象*重载赋值运算符重载赋值运算符“=” 如用户如用户没有没有为一个类为一个类重载赋值运算符重载赋值运算符,编译程序将生成一,编译程序将生成一个个默认赋值运算符函数默认赋值运算符函数。赋值运算把。赋值运算把源对象的数据成员源对象的数据成员逐逐个地个地复制到目的对象的相应数据成员复制到目的对象
35、的相应数据成员对于一般的类,使用对于一般的类,使用默认赋值运算符函数默认赋值运算符函数都能都能正常地工作正常地工作,但当一个类中包含有但当一个类中包含有指针类型指针类型的的数据成员数据成员,并且通过,并且通过指针指针在构造函数中在构造函数中动态申请了存储空间动态申请了存储空间,在,在析构函数析构函数中通过指中通过指针针释放释放了了动态存储空间动态存储空间,这种情况可能会出现运行时错误,这种情况可能会出现运行时错误例例4.9 使用赋值运算符出现运行时错误的示例。使用赋值运算符出现运行时错误的示例。class Stringprivate:/ 数据成员数据成员char *strValue;/ 串值串
36、值public:/ 公有成员公有成员String(char *s = )/ 构造函数构造函数if (s = NULL) s = ;/ 将空指针转化为空串将空指针转化为空串strValue = new charstrlen(s) + 1;/ 分配存储空间分配存储空间strcpy(strValue, s);/ 复制串值复制串值String(const String ©)/ 复制构造函数复制构造函数strValue = new charstrlen(copy.strValue) + 1;/ 分配空间分配空间strcpy(strValue, copy.strValue);/ 复制串值复制串值S
37、tring() delete strValue; / 析构函数析构函数void Show() const cout strValue endl; / 显示串显示串;例例4.9 使用赋值运算符出现运行时错误的示例。使用赋值运算符出现运行时错误的示例。int main()/ 主函数主函数main()String s1(try), s2;/ 定义对象定义对象s2 = s1;/ 使用默认赋值运算符函数使用默认赋值运算符函数s1.Show();/ 显示串显示串s1s2.Show();/ 显示串显示串s2system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0
38、, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:trytry请按任意键继续请按任意键继续. . .当用户按任一键时,屏幕将会显示类似当用户按任一键时,屏幕将会显示类似Debug Assertion Failed!的错误的错误 在在Dev-C+和和MinGW Developer Studio环境中没有出上述错误现环境中没有出上述错误现象,原因是在发现象,原因是在发现delete释放一个已释放的空间时,不再作释放操释放一个已释放的空间时,不再作释放操作,也不作异常处理作,也不作异常处理 在执行在执行“String s1(try);”语句时,构造函数动态地分配存储空间,并
39、将返语句时,构造函数动态地分配存储空间,并将返回的地址赋给对象回的地址赋给对象s1的数据成员的数据成员strValue,然后把,然后把“try”拷贝到这块空间中拷贝到这块空间中执行语句执行语句“s2 = s1;”时,由于没有为类时,由于没有为类String重载赋值运算符,系统将调用重载赋值运算符,系统将调用默认赋值运算符函数,负责将对象默认赋值运算符函数,负责将对象s1的数据成员的数据成员strValue中存放的地址值赋中存放的地址值赋值给对象值给对象s2的数据成员的数据成员strValue对象对象s1复制给对象复制给对象s2的仅是其数据成员的仅是其数据成员strValue的值,并没有把的值,
40、并没有把strValue指指向的动态存储空间进行复制,当遇到对象的生命期结束需要撤销对象时,首向的动态存储空间进行复制,当遇到对象的生命期结束需要撤销对象时,首先由先由s2对象调用析构函数,将对象调用析构函数,将strValue成员所指向的字符串成员所指向的字符串“try”所在的动所在的动态空间释放态空间释放在对象在对象s1自动调用析构函数之前,对象自动调用析构函数之前,对象s1的数据成员的数据成员strValue指向已释放的指向已释放的内存空间,因此在内存空间,因此在s1调用析构函数时,无法正确执行析构函数代码调用析构函数时,无法正确执行析构函数代码“delete strValue”,从而导
41、致出错。,从而导致出错。重载赋值运算符解决问题重载赋值运算符解决问题应重载赋值运算符,复制指针数据成员应重载赋值运算符,复制指针数据成员strValue所指向的动态空间中的内容。这样,两个对象的所指向的动态空间中的内容。这样,两个对象的指针成员指针成员strValue就拥有不同的地址值,指向不就拥有不同的地址值,指向不同的动态存储空间同的动态存储空间例例4.10 重载赋值运算符避免例重载赋值运算符避免例4.9使用默认赋值运算符的副作用。使用默认赋值运算符的副作用。class Stringprivate:/ 数据成员数据成员char *strValue;/ 串值串值public:/ 公有成员公有
42、成员String(char *s = )/ 构造函数构造函数if (s = NULL) s = ;/ 将空指针转化为空串将空指针转化为空串strValue = new charstrlen(s) + 1;/ 分配存储空间分配存储空间strcpy(strValue, s);/ 复制串值复制串值String(const String ©)/ 复制构造函数复制构造函数strValue = new charstrlen(copy.strValue) + 1;/ 分配空间分配空间strcpy(strValue, copy.strValue);/ 复制串值复制串值String operator=(
43、const String ©);/ 重载赋值运算符重载赋值运算符String() delete strValue; / 析构函数析构函数void Show() const cout strValue endl; / 显示串显示串;例例4.10 重载赋值运算符避免例重载赋值运算符避免例4.9使用默认赋值运算符的副作用。使用默认赋值运算符的副作用。String String:operator=(const String ©) / 重载赋值运算符重载赋值运算符if (this != ©)/ 目的对象与源对象不是同一个对象目的对象与源对象不是同一个对象strValue = ne
44、w charstrlen(copy.strValue) + 1;/ 分配空间分配空间strcpy(strValue, copy.strValue);/ 复制串值复制串值return *this;/ 返回目的对象返回目的对象int main()/ 主函数主函数main()String s1(try), s2;/ 定义对象定义对象s2 = s1;/ 使用重载赋值运算符使用重载赋值运算符s1.Show();/ 显示串显示串s1s2.Show();/ 显示串显示串s2system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运
45、行时屏幕输出如下:程序运行时屏幕输出如下:trytry请按任意键继续请按任意键继续. . .4.3.2 重载自增重载自增1运算符运算符“+”和自减和自减1运算符运算符“-” 这两个运算符还有前缀和后缀的差别,这两个运算符还有前缀和后缀的差别,+a和和-a是前缀使用方是前缀使用方式,式,a+和和a-是后缀使用方式是后缀使用方式在当前的在当前的C+标准中,对此作了特殊约定,对于标准中,对此作了特殊约定,对于前缀前缀使用方式,使用方式,与与一般单目运符的重载方式相同一般单目运符的重载方式相同,对于,对于后缀后缀使用方式,在进行使用方式,在进行运算符的重载函数中运算符的重载函数中增加一个整型参数增加一
46、个整型参数具体重载函数的声明格具体重载函数的声明格式如下:式如下:类名类名 operator+();/ 前缀前缀 “+”重载为类的成员函数重载为类的成员函数 类名类名 operator+(int);/ 后缀后缀 “+”重载为类的成员函数重载为类的成员函数 类名类名 operator-();/ 前缀前缀 “-”重载为类的成员函数重载为类的成员函数 类名类名 operator-(int);/ 后缀后缀 “-”重载为类的成员函数重载为类的成员函数 friend 类名类名 operator+(类名类名 &);/ 前缀前缀 “+”重载为类的友元函数重载为类的友元函数 friend 类名类名 operat
47、or+(类名类名 &, int); / 后缀后缀 “+”重载为类的友元函数重载为类的友元函数 friend 类名类名 operator-(类名类名 &);/ 前缀前缀 “-”重载为类的友元函数重载为类的友元函数 friend 类名类名 operator-(类名类名 &, int);/ 后缀后缀 “-”重载为类的友元函数重载为类的友元函数 类名类名 operator+(类名类名 &);/ 前缀前缀 “+”重载为普通函数重载为普通函数 类名类名 operator+(类名类名 &, int);/ 后缀后缀 “+”重载为普通函数重载为普通函数 类名类名 operator-(类名类名 &);/ 前缀前缀
48、 “-”重载为普通函数重载为普通函数 类名类名 operator-(类名类名 &, int);/ 后缀后缀 “-”重载为普通函数重载为普通函数例例4.11重载自增重载自增1运算符运算符“+”和自减和自减1运算符运算符“-”示例。示例。class Integerprivate:/ 数据成员数据成员int num;/ 数据值数据值public:/ 公有函数公有函数Integer(int n = 0): num(n) / 构造函数构造函数void Set(int n) num = n; / 设置数据值设置数据值int Get() const return num; / 返回数据值返回数据值Integ
49、er operator+() return Integer(+num); / 前缀前缀“+Integer operator+(int i) return Integer(num+); / 后缀后缀+friend Integer operator-(Integer &a)/ 前缀前缀- return Integer(-a.num); ;Integer operator-(Integer &a, int i)/ 重载后缀重载后缀-为普通函数为普通函数 Integer tem = a;/ 用用tem暂存暂存aa = Integer(a.Get() - 1);/ a的值减的值减1return tem;
50、/ 返回返回a原来的值原来的值,也就是也就是tem例例4.11重载自增重载自增1运算符运算符“+”和自减和自减1运算符运算符“-”示例。示例。int main()/ 主函数主函数main()Integer i, j;/ 定义整型对象定义整型对象i.Set(6);/ 设置数据值设置数据值j = +i;/ 对对i作前缀自增作前缀自增1运算运算,+i等价于等价于i.operator+()cout i.Get() , j.Get() endl;/ 输出数据值输出数据值7,7i.Set(6);/ 设置数据值设置数据值j = i+;/ 对对i作后缀自增作后缀自增1运算运算,+i等价于等价于i.operat
51、or+(0)cout i.Get() , j.Get() endl;/ 输出数据值输出数据值7,6i.Set(6);/ 设置数据值设置数据值j = -i;/ 对对i作前缀自减作前缀自减1运算运算,-i等价于等价于operator-(i)cout i.Get() , j.Get() endl;/ 输出数据值输出数据值5,5i.Set(6);/ 设置数据值设置数据值j = i-;/ 对对i作后缀自减作后缀自减1运算运算,i-等价于等价于operator-(i, 0)cout i.Get() , j.Get() endl;/ 输出数据值输出数据值5,6system(PAUSE);/ 输出系统提示信息
52、输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统*4.3.3 重载下标运算符重载下标运算符“” 下标运算符下标运算符“ ”一般用于在一般用于在数组数组中标识数组中标识数组元素元素的位置的位置,在,在C/C+语言中,下标运算符语言中,下标运算符“ ”是是没没有越界检查功能有越界检查功能的。可以通过重载的。可以通过重载下标运算符下标运算符“”实现一种更安全、功能更强的数组类型实现一种更安全、功能更强的数组类型下标运算符的使用方式是下标运算符的使用方式是ai,第一个操作数第一个操作数为数为数组名,重载后就为组名,重载后就为用户自定义对象用户自定义对象,因此,因此C+
53、规规定重载下标运算符定重载下标运算符“”只能重载为类的成员函只能重载为类的成员函数。定义下标运算符数。定义下标运算符“ ”的函数重载的一般声明的函数重载的一般声明格式如下:格式如下: 返回值类型返回值类型 &operator (int); 例例4.12 重载下标运算符重载下标运算符“”示例。示例。/ 声明数组类模板声明数组类模板template class Arrayprivate:/ 数据成员数据成员ElemType *elem;/ 存储数据元素值存储数据元素值int size;/ 数组元素个数数组元素个数public:/ 公有函数公有函数Array(int sz): size(sz) el
54、em = new ElemTypesize; / 构造函数构造函数Array() delete elem; / 析构函数析构函数ElemType &operator(int i)/ 下标运算符下标运算符重载为成员函数重载为成员函数if (i = size)cout 元素位置错元素位置错! endl;exit(1);/ 退出程序的运行退出程序的运行,返回到操作系统返回到操作系统return elemi;/ 返回返回elemi;例例4.12 重载下标运算符重载下标运算符“”示例。示例。int main()/ 主函数主函数main()int a = 1, 9, 7, 5, 6, 3;/ 定义数组定义
55、数组aint n = 6;/ 数组元素个数数组元素个数Array obj(n);/ 定义数组对象定义数组对象int i;/ 定义临时变量定义临时变量for (i = 0; i n; i+) obji = ai;/ obji等价于等价于obj.operatorifor (i = 0; i n; i+) cout obji ;/ 输出元素值输出元素值cout endl;/ 换行换行system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出如下:程序运行时屏幕输出如下:1 9 7 5 6 3请按任意键继续请按任
56、意键继续. . .*4.3.4 重载函数调用运算符重载函数调用运算符“()()” 重载重载函数调用运算符函数调用运算符“()()”的用途是使类的的用途是使类的对象对象可以象可以象函数名函数名称一样使用,运算符称一样使用,运算符“()()”是通过是通过用户用户自定义对象自定义对象来调用函数,也就是用户来调用函数,也就是用户自定义自定义对象对象是是第一个操作数第一个操作数,因此,因此C+规定函数调用运规定函数调用运算符算符“()()”只能重载为类的只能重载为类的成员函数成员函数,具体声明,具体声明格式如下:格式如下: 返回值类型返回值类型 operator()(形参表形参表);在在C +中,由于上
57、面的声明格式中形参表的参数中,由于上面的声明格式中形参表的参数个数不确定个数不确定,因此,因此 “()()”是是不确定目数运算符不确定目数运算符例例4.13 重载下标运算符重载下标运算符“”示例。示例。/ 声明数组类模板声明数组类模板template class Arrayprivate:/ 数据成员数据成员ElemType *elem;/ 存储数据元素值存储数据元素值int size;/ 数组元素个数数组元素个数public:/ 公有函数公有函数Array(int sz): size(sz) elem = new ElemTypesize; /构造函数构造函数Array() delete e
58、lem; /析构函数析构函数ElemType &operator()(int i)/ 函数调用运算符只能重载为成员函数函数调用运算符只能重载为成员函数if (i = size)cout 元素位置错元素位置错! endl;exit(1);/ 退出程序的行运退出程序的行运,返回到操作系统返回到操作系统return elemi;/ 返回返回elemi;例例4.13 重载下标运算符重载下标运算符“”示例。示例。int main()/ 主函数主函数main()int a = 1, 9, 7, 5, 6, 3;/ 定义数组定义数组aint n = 6;/ 数组元素个数数组元素个数Array obj(n);
59、/ 定义数组对象定义数组对象int i;/ 定义临时变量定义临时变量for (i = 0; i n; i+) obj(i) = ai;/ obj(i)等价于等价于obj.operator(i)for (i = 0; i n; i+) cout obj(i) ;/ 输出元素值输出元素值cout ”和输出运算符和输出运算符“”和输出运算符和输出运算符“”就能对标准类型数据进行输入和输出。就能对标准类型数据进行输入和输出。对于用户自定义的对象,是不能直接用对于用户自定义的对象,是不能直接用“”来进行输来进行输出和输入的。如果要用它们输出和输入自定义的对象,必须对出和输入的。如果要用它们输出和输入自定
60、义的对象,必须对它们进行重载。它们进行重载。输入运算符输入运算符“”和输出运算符和输出运算符“(istream &, 类名类名 &);/ 重载友元函数重载友元函数friend ostream &operator(istream &, 类名类名 &);/ 重载为普通函数重载为普通函数ostream &operator”和和 “”和输出运算符和输出运算符“”和输出运算符和输出运算符“(istream &in, Complex &z)/ 重载输入运算符重载输入运算符double r, i;/ 表示实部表示实部(r)和虚部和虚部(i)cout r;/ 输入实部输入实部cout i;/ 输入虚部输入虚部
61、z.SetReal(r);/ 设置实部设置实部z.SetImage(i);/ 设置虚部设置虚部return in;/ 返回输入流对象返回输入流对象ostream &operator(ostream &out, const Complex &z)/ 重载运算符重载运算符if (z.GetImage() 0) cout z.GetReal() z.GetImage() i;/ 虚部为负虚部为负else if (z.GetImage() = 0) cout z.GetReal();/ 虚部为虚部为0else cout z.GetReal() + z.GetImage() ”和输出运算符和输出运算符“ z;/ 输入输入z, cin z等价于等价于operator(cin, z)cout z endl;/ 输出输出z,coutz等价于等价于operator(cout, z)system(PAUSE);/ 输出系统提示信息输出系统提示信息return 0; / 返回值返回值0, 返回操作系统返回操作系统程序运行时屏幕输出参考如下:程序运行时屏幕输出参考如下:输入实部输入实部:6输入虚部输入虚部:86+8i请按任意键继续请按任意键继续. . .结束结束