28
第 11 第 第第第第第

第11章 运算符重载

  • Upload
    pules

  • View
    129

  • Download
    0

Embed Size (px)

DESCRIPTION

第11章 运算符重载. 11.1 重载运算符的概念. 一个运算符代表一种操作,常用的运算通常可借助一个运算符来实现简单表示,如 a+b 。 C++ 允许对运算符进行重载,实质是对表示某种运算的特殊函数进行重载。. 11.1.1 重载运算符的函数特征. 常见运算对于 C++ 系统的 内置类型 是有效的,但对于 用户定义的数据类型 ,多数运算不再有效。. class Point { int x, y; public: Point(int xv=0, int yv=0) { x = xv; y = yv; } - PowerPoint PPT Presentation

Citation preview

Page 1: 第11章 运算符重载

第 11 章 运算符重载

Page 2: 第11章 运算符重载

一个运算符代表一种操作,常用的运算通常可借助一个运算符来实现简单表示,如a+b 。

C++ 允许对运算符进行重载,实质是对表示某种运算的特殊函数进行重载。

11.1 重载运算符的概念

Page 3: 第11章 运算符重载

Point add(Point& av, Point& bv) { return Point(av.getx()

+bv.getx(), av.gety()+bv.gety());}void main( ){ Point a(1,1), b(2,3), c; //c = a + b; c = add(a, b);}

11.1.1 重载运算符的函数特征 常见运算对于 C++ 系统的内置类型是有效的,但对于用户定义的数据类型,多数运算不再有效。class Point{ int x, y; public: Point(int xv=0, int

yv=0) { x = xv; y = yv; } int getx() { return x; } int gety() { return y; }};

Page 4: 第11章 运算符重载

11.1.1 重载运算符的函数特征( 续 )

增加上述函数实现了对加法运算的重载。 使用方式:

c = a + b; c = operator+(a, b); 运算符重载可以使程序更容易理解,但并不是必需的。

Point operator + ( Point& av, Point& bv ){ return Point(av.getx()+bv.getx(), av.gety()+bv.gety());}

Page 5: 第11章 运算符重载

11.1.1 重载运算符的函数特征( 续 )

如果 @ 代表一个运算符,则“ operator@”是代表 @ 运算的“函数名”。 运算符重载通常是与类定义联系在一起的。

Point operator+( Point& av, int bx ){ return Point(av.getx()+bx, av.gety());}

另一个重载的加法函数

Page 6: 第11章 运算符重载

11.1.2 类重载运算符的两种方法 1. 成员和非成员重载

将运算符重载函数定义为友员(普通函数,非成员)和成员(类的方法)。 class Point{ int x, y; public: Point(int xv=0, int yv=0):x(xv), y(yv){ } Point operator+(Point& bv); //成员重载 friend Point operator+(Point& av, Point& bv); //友员重载};Point Point::operator+(Point& bv) //成员实现{ return Point(x+bv.x, y+bv.y);}Point operator+(Point& av, Point& bv) //友员实现{ return Point(av.x+bv.x, av.y+bv.y);}

Page 7: 第11章 运算符重载

11.1.2 为类重载运算符的两种方法( 续 )

2. 采用成员和非成员重载运算符时的函数原型差异 重要差别 : 函数形参的个数不同。

对于一个 n 目的运算符,使用友员重载时仍需n 个形式参数,而使用成员重载时只有 n-1 个参数 .

原因 : 每个类的非静态方法都有一个缺省的 this 指针作为第一个参数。 类的友元函数则没有 this 指针。

Page 8: 第11章 运算符重载

11.1.2 为类重载运算符的两种方法( 续 )

3. 不同重载方法对运算符使用形式的影响 对于运算符 @ 来说,采用类的成员函数重载时可以“ a@b” 和 a. operator@ ( b ) 两种形式使用运算符,如:

Point a(1,1), b(2,3); Point c = a + b; Point c = a.operator + ( b );

采用友员重载时可以采用运算和函数调用两种语法形式,如: Point d = a + b; Point e = operator+(a, b);

Page 9: 第11章 运算符重载

11.1.2 为类重载运算符的两种方法( 续 )

1 、双目运算符 @ :  成员函数只带一个参数;友元函数带两个参数 aa@bb aa@bb

2 、单目前缀运算符 @ :  成员函数不带参数;友元函数带一个参数     @aa @aa

aa.operator@(bb)operator@(aa, bb)

aa.operator@( )operator@(aa )

Page 10: 第11章 运算符重载

11.1.2 为类重载运算符的两种方法( 续 )

4. 使用成员和非成员重载的限制 必须使用成员而不能使用非成员重载:

= 、 -> 、 ( ) 、 [ ]只能使用友员重载而不能使用类成员重载:

<< 、 >>如果运算符属于赋值类运算,操作中需要修改当前对象( this ),一般使用成员重载:

+= 、 -= 、 *= 、 /= 、 ++ (前置)、 -- (前置)如果运算符的第一个操作数不是当前定义的类类型数据则必须使用友员重载。

Page 11: 第11章 运算符重载

11.1.2 为类重载运算符的两种方法( 续 )

原因:若采用成员时第一个参数必然是this 。

friend Point operator+(int a, const Point& b){ return Point(a+b.x, b.y);}

Page 12: 第11章 运算符重载

11.1.3 重载运算符的限制 ⑴ 只能重载 C++ 已有的运算符,不能臆造。 ⑵ 重载时应尽量保持运算符原来的意义,不应“挪为他用”。 ⑶ 不能改变运算符的本来特性,包括操作数个数、优先级别和结合次序。 ⑷ 不能改变运算符对基本类型数据的操作方式,不能定义只有内置类型数据为参数的运算符重载。 (5) 以下 5 个 C++ 运算符不能被重载:. (成员访问运算符)、 .* (成员指针访问运算符)、:: (域解析符)、 ?: (条件运算符)、 sizeof

Page 13: 第11章 运算符重载

11.2 重载运算符函数的设计 1. 重载运算符的返回值

运算符函数的返回值类型一般都与当前类的类型有关。运算符函数返回对象的值还是对象引用

原则:如果运算符形成的表达式(函数调用表达式)需要作为左值则返回引用,否则返回值。

Page 14: 第11章 运算符重载

11.2 重载运算符函数的设计 ( 续 )

⑴+ 、-、 * 、 / 、 % 、后置的 ++ 和 -- 因为加法、减法、乘法、除法和后置的加 1 和减 1 表达式不能做左值,重载时应返回对象的值,故应采用类似如下的函数原型: Point operator+(...); Point operator++(...);

⑵= 、 [ ] 、前置的 ++ 和 -- 由于赋值表达式、下标引用变量和前置的加 1 、减 1 表达式都可做左值,故应返回对象的引用,如: Point& operator=(...); char& operator[](...);

Page 15: 第11章 运算符重载

11.2 重载运算符函数的设计 ( 续 )

2. 运算符函数的引用参数当运算符需要操作类的对象时,应确定该使用指针还是引用做函数的参数。一般不直接使用类对象做参数,其中的一个重要原因是效率。 此外,如果运算符函数中不修改被引用对象的值,通常要对参数进行常量限制,如:

Point operator+(const Point& a, const Point& b);

Page 16: 第11章 运算符重载

11.3 若干常见运算符的重载 一些其它重要的运算符重载。

Page 17: 第11章 运算符重载

11.3.1 重载增量运算符 ++

1. 前置的 ++ 前置 ++ 遵循一般的单目运算符重载规范,但由于可以作为左值,故函数应该返回当前对象的引用。 class Point

{ int x, y; public: Point(int xv=0, int yv=0){ x = xv; y = yv; } Point& operator++( ); //成员重载};Point& Point::operator++( ) //成员实现{++ x; ++ y; //当前对象的坐标

加 1 return *this; //返回当前对象引用}

Page 18: 第11章 运算符重载

11.3.1 重载增量运算符 ++( 续 )

Point a(1,2), b;b = ++a;由于前置 ++ 运算返回的是已经加 1 之后的当前对象,故

b 的值为 (2,3) 。如果使用友员重载,应以如下代码实现: // 在类 Point 定义中的函数声明friend Point& operator++(Point& a);

Point& operator++(Point& a) // 作为普通函数实现{ ++ a.x; ++ a.y; return a;}

Page 19: 第11章 运算符重载

11.3.1 重载增量运算符 ++( 续 )

2. 后置的 ++ 将后置 ++ 运算视为二元运算,且第二个运算数是 int 类型,即后置运算表达式 a++ 被视为 a+0 。 后置 ++ 是普通加法运算,不能作为左值,故返回值只是对象值而不是引用。

Page 20: 第11章 运算符重载

11.3.1 重载增量运算符 ++( 续 )

Point operator++(int); Point Point::operator++(int) { Point t(x, y); x++; y++; return t; }

friend Point operator++(Point& a, int);Point operator++(Point& a, int){ Point t(a.x, a.y); a.x++; a.y++; return t; }

重载后的后置加运算符可以按如下方式调用:Point a(1,2);a++;operator++(a, 0); a.operator++( 0 );

见exam_13后置 ++

Page 21: 第11章 运算符重载

11.3.2 重载赋值运算符 =

C++ 会为每个类提供一个缺省的赋值运算符,因此,在对象之间可以直接赋值。 对于 Point 类,下面的代码可以正常工作:

Point a(1, 2), b; b = a;

赋值运算的实质是利用一个对象来重新改写一个已有的对象,为了避免两个对象占用同一份资源如内存区,不能直接进行数据按位复制,需要修改缺省的赋值行为。

Page 22: 第11章 运算符重载

11.3.2 重载赋值运算符 =( 续 )

赋值运算必须使用成员重载,且因为赋值运算可做左值,故应返回对象的引用。 String& operator=(const String& copy);

赋值运算本质上是析构函数和构造函数的结合体,含义是拆除原对象,再根据右值构造新对象。

Page 23: 第11章 运算符重载

11.3.3 重载下标运算符 []

C++ 中,在重载下标运算符时,认为它是一个双目运算符,例如: X[Y] X 为左操作数  Y 为右操作数 格式:

返回类型 类名 ::operator[ ] (形参) { // 函数体 } 其中形参表示下标,并且只能有一个参数

下标运算符重载定义只能使用成员函数 X[5] 被解释为 X.operator[ ]( 5 )

Page 24: 第11章 运算符重载

11.3.3 重载下标运算符 [] (续) 若想使 String 对象像 C字符串那样支持对字符的索引,这需要为 String 增加一个下标运算符函数。

// 在 String 类定义中增加的声明inline char& operator[](int index);// 类定义外的实现inline char& String::operator[](int index){ return str[index];}函数的返回值是引用,其目的是支持类似下面的语法:String s("a string.");s[2] = ’x’;经过重载后的 s[k] 如同 C 中的字符数组元素一样,是一个普通的 char 型变量,可读可写。

Page 25: 第11章 运算符重载

11.3.4 重载类型转换运算符 重载类型转换运算符可以将一个对象表达式转换为其它类型的数据。 类型转换运算为单目运算,必须用成员重载。 将 Point 对象转换为 double 型,结果是点的坐标到原点的距离。

operator double(); // 在 Point 类定义中增加的声明Point::operator double() // 在 Point 类定义之外的代码实现 { return sqrt(x*x + y*y); // 需要 cmath 头文件支持}程序中可以很容易地使用重载后的“距离运算”:Point a(10, 20);double b = double(a);

Page 26: 第11章 运算符重载

11.3.4 重载类型转换运算符 (续) 应注意类型转换运算的特殊形式:

⑴double 是转换后的类型,可以是 C++ 的内置类型或用户定义的类型。 将 Point 对象转换为一个 C字符串, operator char*(); // 在 Point 类定义中的声明

⑵无参数,因为缺省的 this 指针给出了被转换的当前对象。⑶ 函数没有返回类型,事实上,函数的返回类型已包含在名字中,此例为 double 。

Page 27: 第11章 运算符重载

运算符函数调用形式比较

Page 28: 第11章 运算符重载

*11.3.5 重载函数调用运算符与函数对象 此部分内容自学。