Presentation is loading. Please wait.

Presentation is loading. Please wait.

Object-Oriented Programming in C++ 第四章 运算符重载

Similar presentations


Presentation on theme: "Object-Oriented Programming in C++ 第四章 运算符重载"— Presentation transcript:

1 Object-Oriented Programming in C++ 第四章 运算符重载
中国科大学继续教育学院 李艺

2 第一章 C++的初步知识 第二章 类和对象 第三章 再论类和对象 第四章 运算符重载 第五章 继承与派生 第六章 多态性与虚函数 第七章 输入输出流 第八章 C++工具

3 4.1 什么是运算符重载 4.2 运算符重载的方法 4.3 运算符重载的规则 4.4 重载双目运算符 4.5 重载单目运算符 4.6 重载流插入和流提取运算符 4.7 不同类型数据间的转换

4 Like most languages, C++ supports a set of operators for its built-in types.
However, most concepts for which operators are conventionally used are not built-in types in C++, so type must be represented as user-defined types. For example, if you need complex arithmetic, matrix algebra, logic signals, or character strings in C++, you use classes to represent these notions. Defining operators for such classes sometimes allows a programmer to provide a more conventional and convenient notation for manipulating objects than could be achieved using only the basic functional notation.

5 4.1 什么是运算符重载 在第一章中我们已经介绍了重载的概念,所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之具有新的功能。重载也就是一名多用。 现在要讨论的问题是,用户可不可以对C++提供的运算符进行重载?即对运算符一名多用。 比如,复数加法运算,C++只能编写一个加法函数进行复数的加法。而不能直接用“+”号进行两个复数相加。 下面看看教材120页的例程。

6 4.1 什么是运算符重载 #include <iostream.h> class complex {public:
complex ( ) { real = 0;image = 0; } complex (double r, double i) { real = r; image = i; } complex add (complex &c2); void display( ); private: double real, image; }; complex complex::add (complex &c2) { complex c; c.real = real + c2.real; c.image = image + c2.image; return c; } void complex::display( ) { cout << “( “ << real << “,” << image << “i )” << endl; } Int main( ) { complex c1(3,4), c2(5,-10), c3; c3=c1.add(c2); cout << “c1 = “; c1.display( ); cout << “c2 = ”; c2.display( ); cout << “c1+c2 = “; c3.display( ); return 0; 可见这种方式烦琐、不方便。可不可以用 c3=c1+c2 的形式来表达呢? 我们的回答是,只要对“+”号进行重载,复数加法就可以写成这种形式。

7 4.2 运算符重载的方法 运算符重载的方法: 定义一个重载运算符的函数; 在需要执行重载的运算符时,系统就自动调用该重载的运算符函数
重载运算符函数的一般格式: 函数类型 operator 运算符名称 ( 形参表列 ) { 对运算符的重载处理 } 注意: operator 是关键字,专门用于定义重载运算符。 运算符名称就是C++提供给用户的预定义名称。如:+、-、*、/、<、<<、>>、>等等。

8 4.2 运算符重载的方法 我们定义一个重载的运算符“+”的成员函数,然后使用“+”进行复数加法:
# include <iostream.h> class complex { double real, image; public: complex (double r = 0, double i = 0) { real = r; image = i;} void show( ) {cout<<real<<'+'<<image<<"i"<<endl; } complex operator+(const complex &op); }; complex complex::operator+ (const complex &op) {complex temp; temp.real = real + op.real; temp.image = image + op.image; return temp ; } void main( ) { complex ob1(1.5, 3.0), ob2(1.0, 5.0); complex sum; sum = ob1 + ob2; sum.show( ); }

9 还是复数加法,我们将运算符+重载为友元函数:
#include <iostream.h> class complex { private: double real,image; public: complex(double r=0,double i=0):real(r),image(i){}; void show() { cout<<real<<((image>=0)?'+':'\a') <<image<<'i'<<endl; } friend complex operator+(const complex &op1, const complex &op2); }; complex operator+ (const complex &op1, const complex &op2) { complex temp; temp.real=op1.real+op2.real; temp.image=op1.image+op2.image; return temp; } void main() { complex ob1(1.5,3),ob2(1,4.5); complex sum,sub; sum=ob1+ob2; sum.show(); 还是复数加法,我们将运算符+重载为友元函数:

10 还是复数加法,我们将运算符+重载为普通函数:
# include <iostream.h> class complex {public: double real, image; complex (double r = 0, double i = 0) { real = r; image = i;} void show( ) {cout<<"real = "<<real<<' '<<"image = "<<image<<endl; } }; complex operator+ (const complex &op1, const complex &op2) {complex temp; temp.real = op1.real + op2.real; temp.image = op1.image + op2.image; return temp; void main( ) { complex ob1(1.5, 3.0), ob2(1.0, 5.0); complex sum; sum = ob1 + ob2; sum.show( ); 还是复数加法,我们将运算符+重载为普通函数:

11 4.3 运算符重载的规则 运算符重载的规则: C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。比如,有的人学过BASIC,想把它的幂运算符“**”拿过来,重载为C++的幂运算符,这是不行的。 C++不允许重载的运算符:大多数C++运算符都允许重载。不能重载的运算符只有5个: “.”:成员访问运算符; “.*”:成员指针访问运算符; “::”:域运算符; “sizeof”:长度运算符; “?:”:条件运算符。

12 4.3 运算符重载的规则 重载不能改变运算符运算对象(即操作数)的个数。比如,双目运算符不能变成三目运算符。 重载不能改变运算符的优先级。
重载不能改变运算符的结合性。比如,从右至左运算的赋值号,重载后不能变成从左至右运算的顺序。 重载运算符的函数不能有默认的参数。否则就改变了运算符参数的个数不变的规定。 重载运算符函数的参数不能全是标准数据类型,以防止用户篡改用于标准类型数据的运算性质,避免混乱。如: int operator + (int a, int b ) { return a – b; } 如果有表达式4+3,它的结果是7 呢还是1 ?

13 4.3 运算符重载的规则 用于类对象的运算符一般必须重载,但运算符“=”和“&”,用户不必重载。 运算符重载函数可以是: 类的成员函数;
可以是类的友元函数; 也可以是普通函数。 下面我们来详细讨论这集中重载方式。

14 4.4 重载双目运算符 #include <iostream.h> #include <string.h> class String { private: char *buffer; int length; public: String(); String(char *ptr); String(const String &str); ~String(); void show(); String operator+(String &str); String operator=(String &str); }; String::~String() { delete []buffer; } String::String() //缺省构造函数 { length=0; buffer=new char; *buffer='\0'; //buffer置空 } String::String(char *ptr) { length=strlen(ptr); buffer=new char[length+1]; strcpy(buffer,ptr); } String::String(const String &str) { length=str.length; strcpy(buffer,str.buffer); } 双目运算符(也叫二元运算符)有两个操作数,通常在运算符的左右两侧。如 3+5,a=c 等。重载双目运算符时,函数中应该有两个参数。 请看左边例程,我们重载+运算符和赋值运算符=。 双目运算符一般重载为友元函数。以避免交换律的破坏。

15 void String::show() { cout<<buffer<<endl; } String String::operator + (String &str) //重载+,字串连接 { String temp; temp.length=length+str.length; temp.buffer=new char[temp.length+1]; strcpy(temp.buffer,buffer); //将第一操作数字串拷贝进临时字串 strcat(temp.buffer,str.buffer); //将临时字串与第二操作数字串连接 return temp; } String String::operator =(String &str) { //重载=,字串赋值 y=x,this 值是y的地址,&str是对象x的地址 if (this==&str) return *this; //若x与y相同,不作处理。 delete [] buffer; // 若x与y不同,释放y原有字符串占用的内存 length=str.length; // 然后开辟有的新缓冲区,并将x中的内容拷贝给y buffer=new char[length+1]; strcpy(buffer,str.buffer); return *this; void main( ) { String str1("Hello,"),str2("C++"); String x,y; x=str1+str2; x.show( ); y=x; y.show( );

16 4.5 重载单目运算符 单目运算符只有一个操作数(如 !a, -b, ++i, - -j 等),因此重载函数只有一个参数,如果重载函数为成员函数,还可以省约此参数。 左边例程,将“-”重载成友元函数。 单目运算符一般重载为成员函数 #include <iostream.h> class complex { private: double real,image; public: complex(double r=0,double i=0):real(r),image(i){}; void show() { cout<<real; if (image>0) cout<<'+'<<image<<'i'<<endl; else cout<<image<<'i'<<endl; } friend complex operator-(complex &com); }; complex operator-(complex &com) { return complex(-com.real,-com.image); } void main() { complex ob1(1,-4.5),ob2; ob2=-ob1; ob2.show(); }

17 4.6 重载流插入和流提取运算符 C++的流插入运算符“<<”和流提取运算符“>>”是在类库中提供的,分别是istream类和ostream类。cin 和 cout 分别是istream和 ostream 类的对象。在类库提供的头文件中已经对“<<”和“>>”进行了重载,使之成为流流插入、流提取运算符,以进行数据的输入和输出。 凡是用 cout<< 和 cin>> 进行输入输出的,都要用 #include <iostream.h> 语句,把头文件包含到本程序中。 用户自己定义的类型的数据,不能直接用<<、>>来输入输出,必须进行重载才行。

18 4.6 重载流插入和流提取运算符 重载流插入运算符
我们希望“<<” 运算符不仅能输出标准数据类型,而且能输出用户自己定义的类对象。我们以复数对象输出为例。 #include <iostream.h> class complex {public: complex( ){real = 0; image = 0;} complex (double r, double i ) { real = r; image = i; } complex operator + ( complex &c2); friend ostream & operator << (ostream&, complex&); private: double real, image; } ; complex complex :: operator +(complex &c2) { return complex (real+c2.real, image+c2.image); } ostream& operator << (ostream& output, complex& c) {output<<“(”<<c.real<<“+” <<c.image<<“i)”<<endl; return output; } void main( ) { complex c1(2,4), c2(3,5), c3; c3 = c2+c1; cout<<c1; cout<<c2; cout << c3; }

19 4.6 重载流插入和流提取运算符 重载流提取运算符
我们希望“>>” 运算符不仅能输入标准数据类型,而且能输入用户自己定义的类对象。我们仍以复数对象输入出为例。 #include <iostream.h> class complex {public: friend ostream & operator << (ostream&, complex&); friend istream & operator >> (istream&, complex&); private: double real, image; } ; ostream& operator << (ostream& output, complex& c) {output<<“(”<<c.real<<“+” <<c.image<<“i)”<<endl; return output; } istream& operator >> (istream& input, complex& c) {cout<<“ 请输入复数的实数部分和虚数部分 ”<<endl; input>>c.real>>c. image; return input; } void main( ) { complex c1, c2; cin>>c1>>c2; cout<<“c1=“<<c1<<endl; cout<<“c2=“<<c2<<endl; }

20 4.7 不同类型数据间的转换 标准类型数据间的转换 标准数据间的自动转换:C++支持不同类型数据间的自动转换。比如:
int i = 6; i = i; 求解表达式时,编译系统先将整数6转换成double类型6.0,再与7.5相加,和为13.5,然后在赋给整数变量 i 之前,将13.5转换成整数13,并赋给变量 i 。 显式类型转换:C++还支持标准数据间的显式数据类型转换,格式为: 数据类型名 (数据) 注意,它与C语言格式不同,C语言是 (数据类型名) 数据 C++保留了C语言的格式,但提倡用C++的格式。例如, int (13.6);结果等于13。

21 4.7 不同类型数据间的转换 转换构造函数:即conversion constructor function,它的作用是将一个其他类型的数据转换成指定类的对象。到现在为止,我们已经介绍了以下集中构造函数: 默认构造函数:如complex ( ); 用于初始化的构造函数:如complex (double r, double i) 复制构造函数:如 complex (complex &c); 转换构造函数:只有一个形参,如: complex (double r) { real = r; image = 0; } 其作用是将double 型参数 r 转换成 complex 类的对象,将 r 作为复数的实部,虚部为0。 用户可以根据需要自己定义转换构造函数,在函数体中告诉编译系统,怎样进行转换。

22 4.7 不同类型数据间的转换 假设程序已经定义了上面介绍的complex类,和 complex转换构造函数,那么:
complex c1(3.6) // 建立c1对象,由于只有一个参数,调用转换构造函数 complex (13.6 ) // 建立无名对象,合法,但无法使用,此为类型转换 c1 = complex (13.6) // 假设已定义c1为complex类,合法,类型转换 转换构造函数将指定的数据类型转换成类对象的方法: 先声明一个类( 如complex ); 在该类中定义一个转换构造函数,参数类型是待转换的类型。 在该类的作用域内,用以下形式进行类型转换: 类名 (待转换类型的数据);

23 4.7 不同类型数据间的转换 类型转换函数 C++用转换构造函数将指定类型的数据转换成类对象,但反过来做,转换构造函数不行。
C++用类型转换函数( type conversion function )来解决这个问题。 类型转换函数的作用:将一个类的对象转换成另一类型的数据。省去了对不同的运算符一一重载的麻烦。 类型转换函数的格式: operator 类型名( ) // 不能指定函数类型,被重载的是类型名 { 实现转换的语句 } // 函数没有参数 例如,已经声明了一个complex类,可以在类中定义如下的类型转换函数: operator double( ) // double类型重载后除了原有含义, { return real; } // 还有将complex对象转换成double类型的含义

24 4.7 不同类型数据间的转换 转换构造函数和类型转换函数有一个共同的特点:仅在需要的时候,系统会自动调用这些函数。
例如,若已定义double变量到 d1,d2,complex对象 c1,c2。且类中已定义了类型转换函数,设程序有以下表达式: d1 = d2 + c1 编译系统发现“+”左侧的d2是double型,右侧c1是 complex对象,如果没有对“+”重载,就会检测有无类型转换函数,结果发现对double的重载函数,就调用该函数,将complex对象c1转换成double型数据,建立了一个临时的double型变量,并与d2相加,最后将double 型的合数赋给变量d1。

25 4.7 不同类型数据间的转换 如果类中定义了转换构造函数,并将“+”运算符重载为complex类的友元函数,但没有类型转换函数,若有以下表达式: c2 = c1 + d2; 系统发现“+”的左侧c1是complex对象,右侧d2是double型数据。 于是寻找有没有“+”的重载函数,发现有,但是,是友元函数,需要两个complex对象作为参数进行相加,而d2是double,不合要求。 寻找有没有对double进行重载(即类型转换函数),没有。因此不能把c1转换成double类型, 寻找有无转换构造函数,发现有,调用complex(d2),建立临时的complex对象,再调用operator +函数,将两个复数相加,然后赋给 c2。表达式相当于: c2 =c1 + complex (d2);

26 4.7 不同类型数据间的转换 类型转换函数也使用operator关键字,因此也称为“类型转换运算符重载函数”。下面是一个运算符重载、转换构造函数的综合程序: #include <iostream.h> class complex {public: complex( ){ real=0; image=0; } complex (double r)//转换构造函数 { real=0; image=0; } complex (double r, double i) { real = r; image = i; } friend complex operator +(complex c1, complex c2) void display( ) private: double real, image; }; void complex::display( ) { cout<<“(“<<real<<“,” <<image<<“i)”<<endl; } complex operator +(complex c1, complex c2) { // 运算符重载为友元 return complex (c1.real+c2.real, c1.image+c2.image); void main( ) { complex c1(3,4), c2(5,-10), c3; c3 = c1+ 2.5; c3.display( );

27 4.7 不同类型数据间的转换 程序分析: 如果没有定义转换构造函数,程序出错,因为即使重载运算符,也不能让complex对象与double数据相加。 定义了转换构造函数,也重载了“+”运算符,在处理c1+2.5时,编译系统解释为operator +(c1, 2.5),由于2.5不是complex 对象,系统先调用转换构造函数 complex(2.5),建立一个临时对象,其值为( i )。表达式便成为:operator + (c1,complex(2.5)),两对象相加,结果赋给c3。 如果运算符重载为成员函数,其第一个参数必须是本类对象。当第一个操作数不是类对象时,不能将运算符重载为成员函数,否则交换律不适用。

28 4.7 不同类型数据间的转换 一般情况下,将双目运算符重载为友元函数,单目运算符重载为成员函数。
本题中,如果一定要将双目运算符重载为成员函数,而第一操作数又不是类对象时,只有一个办法能够解决,再重载一个运算符“+”,其第一个参数是double型,当然此函数只能是友元,声明格式为: friend operator +(double, complex &); 使用起来显然不太方便。

29 习题: 本章习题请上网查阅教学网页:


Download ppt "Object-Oriented Programming in C++ 第四章 运算符重载"

Similar presentations


Ads by Google