Presentation is loading. Please wait.

Presentation is loading. Please wait.

刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院.

Similar presentations


Presentation on theme: "刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院."— Presentation transcript:

1 刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院
面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院

2 运算符重载 11.1 Introduction 11.2 Fundamentals of Operator Overloading
11.3 Restrictions on Operator Overloading 11.4 Operator Functions as Class Members vs. Global Functions 11.5 Overloading Streaming Insertion and Stream Extraction Operators 11.6 Overloading Unary Operators 11.7 Overloading Binary Operators 11.8 Case Study: Array Class 11.9 Converting between Types 11.10 Case Study: String Class 11.11 Overloading ++ and -- 11.12 Case Study: A Date Class 11.13 Standard Library Class string 11.14 explicit Constructors (自学,了解)

3 运算符重载简介 重载函数(回顾) 运算符重载

4 重载函数(1) 重载函数(overloading)
回顾chap6 重载函数(overloading) 出现在相同作用域中的两个函数,具有相同的名字而形参表不 同,则称为重载函数,它们是不同的函数 形参个数不同 形参类型不同 成员函数可以有const版本的重载,供const对象调用 经常用于创建执行相似任务,但作用于不同数据类型的具有相 同名字的多个函数 square (int x); square (double x); int + int double +double 普通函数重载 运算符(函数)重载 东南大学计算机学院 11/21/2018

5 重载函数(2) 重载函数的匹配 根据实参的类型匹配 根据对象是否为const对象匹配
回顾chap6 重载函数的匹配 根据实参的类型匹配 根据对象是否为const对象匹配 考虑默认值: 若省略实参时,形式与另一个重载函数一致,会产生编译 错误 void f(int a); //调用形式:f(1) void f(int a, int b = 0); //调用形式:f(1,2) 重复声明 东南大学计算机学院 11/21/2018

6 重载函数(3) 函数重载VS.重复声明 若形参表相同而返回类型不同,则第二个声明错误 重复声明: 函数名、返回类型、形参表都相同
回顾chap6 回顾 函数重载VS.重复声明 重复声明: 函数名、返回类型、形参表都相同 若形参表相同而返回类型不同,则第二个声明错误 void f1(int a); void f1(int); typedef A B; void f2(A &); void f2(B &); void f3(int a, int b); void f3(int a, int b = 0); //默认实参不改变形参个数 重复声明 重复声明 重复声明 void f4(A); void f4(const A); void f5(A&); void f5(const A&); void A::f(); void A::f() const; 对副本操作,无法改变实参,因此效果一样 重复声明 传递实参,第一个可改变实参,第二个不可以改变实参,因此效果不一样 函数重载 函数重载 东南大学计算机学院 11/21/2018

7 operator+(double,double)
运算符重载(1) 运算符是一类特殊的函数 3 + 1 运算符重载 operator+(int,int) 重载的运算符函数 operator+(double,double) 东南大学计算机学院 11/21/2018

8 运算符重载(2) 运算符重载的必要性 代码清晰直观,符合人的习惯 根据语义,隐藏实现细节 一般来说,类对象使用运算符必须重载
不可能为用户自定义的类对象预先定义运算规则 函数调用 运算符 a.plus(b); a.minus(b); a = a + b; a = a – b; int x1, y1, a; double x2, y2, b; a = x1 + y1; //int b = x2 + y2; //double 运算符重载是C++可扩展性的一个重要方面 东南大学计算机学院 11/21/2018

9 运算符重载的基础知识 运算符函数 运算符重载方式 类对象的运算符重载

10 运算符函数 需重载的运算符 + 运算符重载函数名 operator+()

11 运算符重载方式 以成员函数重载:non-static成员函数 运算符是对对象的操作,由对象调用 以全局函数重载:一般声明为友元
友元可以访问类的所有数据成员 Complex Complex::operator+(const Complex &) Complex a, b, c; c = a + b; 调用方式: Complex c = a.operator+(b) Complex operator+(const Complex &, const Complex &) 调用方式: Complex c = operator+(a, b) class Complex{ friend Complex operator+(……); …… } 东南大学计算机学院 11/21/2018

12 类对象的运算符重载 类对象使用运算符,必须重载该运算符 三个例外: 赋值运算符 = 取址(&) 逗号(,) 默认的逐个成员赋值(chap9)
(&) 既是“取址”运算符,又是“按位与”运算符 只有当它是取址运算符时才能直接用于对象

13 运算符重载的限制

14 运算符重载的限制(1) 不能创造新的运算符 Appendix A 通过指针的成员指针 通过对象的成员指针 唯一的三元运算符

15 运算符重载的限制(2) 不能改变优先级、结合律 如果希望重载的运算符具有不同的优先级和结合律,只能使用( ) 东南大学计算机学院

16 运算符重载的限制(3) 不能改变元数 一元运算符 二元运算符 三元运算符:不可重载(?:) 元数:运算符的操作数的个数
一元运算符:+1, -1, !, … 二元运算符: a+b, a-b, a*b, a/b, … 三元运算符:?: 一元/二元运算符: + - * & 一元 正号 负号 指针 取址 二元 按位与 重载哪个运算符由元数控制 东南大学计算机学院

17 运算符重载的限制(4) 不能改变对基本类型对象的操作语义 当只包含基本类型对象时,运算符重载不起作用
类库重载了基本类型对象的运算符 当只包含基本类型对象时,运算符重载不起作用 只有当用户自定义类型的对象为操作数时,运算符重载 才起作用 一元运算符:自定义类型的对象 二元运算符:(不考虑顺序) 自定义类型对象 +自定义类型对象 自定义类型对象 + 基本类型对象 东南大学计算机学院 11/21/2018

18 X 运算符重载的限制(5) 只能显式重载,不能自动实现 obj2 = obj1 + obj2 obj2 += obj1 已重载+ +=被重载
东南大学计算机学院 11/21/2018

19 内 容 回 顾 数据抽象和信息隐藏 运算符重载基础 信息隐藏 数据抽象 抽象数据类型ADT 重载函数和运算符重载 运算符重载的限制
不能改变对基本类型对象的操作语义 只有当用户自定义类型的对象为操作数时,运算符重载 才起作用 东南大学计算机学院 11/21/2018

20 内 容 回 顾 两种运算符函数 成员运算符函数:必须是non-static成员函数 全局运算符函数:一般为友元 东南大学计算机学院
11/21/2018

21 11.4 11.7 实现运算符函数: 类成员函数VS. 全局函数 重载一元运算符 重载二元运算符 两种运算符函数 两种运算符函数比较
一元运算符重载 二元运算符重载 重载可交换的运算符 东南大学计算机学院 11/21/2018

22 只能重载一元/二元运算符 二元运算符: 两个操作数 一元运算符: 一个操作数 a + b a – b a * b a / b + a a
二元运算符: 两个操作数 一元运算符: 一个操作数 左操作数 a + b a – b a * b a / b 右操作数 左操作数 + a a ! a a ++ a -- 东南大学计算机学院 11/21/2018

23 两种运算符函数(1) 成员运算符函数:non-static成员函数 运算符是对对象的操作,由对象调用
A a; 一元运算符 + a class A{ public: 返回值类型 operator+( ); }; a.operator+( ) 调用方式: + a 唯一的左操作数作为句柄对象调用成员运算符函数 左操作数必须为A类对象 东南大学计算机学院 11/21/2018

24 两种运算符函数(2) 成员函数实现一元运算符举例 左操作数必须为Complex类对象 Complex a(-3,-1);
Complex b = + a; a = -3 – i b = 3 + i class Complex{ public: Complex operator+( ); private: double realPart; double imaginaryPart; }; Complex Complex::operator+( ) { Complex result(0,0); result.realPart = + realPart; result. imaginaryPart = + imaginaryPart; return result; } b = a.operator+( ) 调用方式: b = + a 左操作数必须为Complex类对象 东南大学计算机学院 11/21/2018

25 两种运算符函数(3) 成员运算符函数:non-static成员函数 二元运算符 调用方式: 左操作数:作为句柄对象调用成员运算符函数
A a; B b; 二元运算符 a + b class A{ public: 返回值类型 operator+(const B &); }; 调用方式: a.operator+( b ) a + b 左操作数:作为句柄对象调用成员运算符函数 右操作数:作为参数传递给成员运算符函数 左操作数必须为A类对象 东南大学计算机学院 11/21/2018

26 两种运算符函数(4) 成员函数实现二元运算符举例 左操作数必须为Complex类对象 Complex a(1,1);
double b = 2.0; Complex c = a + b; a = 1 + i b = 2.0 c = 3 + i class Complex{ public: Complex operator+(double); private: double realPart; double imaginaryPart; }; Complex Complex::operator+(double b) { Complex result(0,0); result.realPart = realPart + b; result. imaginaryPart = imaginaryPart; return result; } c = a.operator+( b ) 调用方式: c = a + b 左操作数必须为Complex类对象 东南大学计算机学院 11/21/2018

27 Complex operator+( const Complex &)
两种运算符函数(5) 成员函数实现二元运算符举例 class Complex{ public: Complex operator+(double); private: double realPart; double imaginaryPart; }; Complex a(1,1); double b = 2.0; Complex c = a + b; //ok. c = a.operator+(b); Complex d = b + a; //error. 若以成员函数方式调用: d = b.operator+(a); 尝试调用double类的成员函数: Complex operator+( const Complex &) 内置类型不能修改! 东南大学计算机学院 11/21/2018

28 两种运算符函数(6) 成员运算符函数的限制 左操作数必须为自定义类A类对象 右操作数可以是任意类类型/基本类型对象
a + b + a 调用方式: a.operator+( ) a.operator+( b ) 左操作数必须为自定义类A类对象 关心操作数的顺序 右操作数可以是任意类类型/基本类型对象 左操作数是其他类/基本类对象时,必须使用全局运算符函数 东南大学计算机学院 11/21/2018

29 两种运算符函数(7) 全局运算符函数重载:一般声明为友元 友元可以访问类的所有数据成员 一元运算符 注意: 是全局函数,而不是类A的成员
A a; 一元运算符 + a 注意: 是全局函数,而不是类A的成员 class A{ friend 返回值类型 operator+( const A & ); }; 返回值类型 operator+(const A &){……} 调用方式: operator+( a ) + a 操作数作为参数传入全局运算符函数 参数必须为自定义类对象/引用(内置类型无法重定义运算符)

30 两种运算符函数(8) 全局函数实现一元运算符举例 Complex a(-3,-1); Complex b = + a; 调用方式:
a = -3 – i b = 3 + i b = operator+(a) 调用方式: b = + a class Complex{ friend Complex operator+( const Complex & ); private: double realPart; double imaginaryPart; }; Complex operator+( const Complex & a){ Complex result(0,0); result.realPart = + a.realPart; result.imaginaryPart = + a.imaginaryPart; return result; } 东南大学计算机学院 11/21/2018

31 参数必须有一个自定义类对象/引用 (内置类型无法重定义运算符)
两种运算符函数(9) 全局运算符函数重载:一般声明为友元 A a; B b; 二元运算符 a + b class A{ friend 返回值类型 operator+(const A &, const B &); }; 注意: 是全局函数,而不是类A的成员 返回值类型 operator+(const A &, const B &){……} 调用方式: operator+(a, b) a + b 操作数作为参数传入全局运算符函数 参数必须有一个自定义类对象/引用 (内置类型无法重定义运算符) 11/21/2018

32 两种运算符函数(10) 全局函数实现二元运算符举例 Complex a(1,1); double b = 2.0;
Complex c = a + b; a = 1 + i b = 2.0 c = 3 + i c = operator+(a,b) 调用方式: a + b class Complex{ friend Complex operator+(const Complex &, double); private: double realPart; double imaginaryPart; }; Complex operator+(const Complex & a, double b) { Complex result(0,0); result.realPart = a.realPart + b; result.imaginaryPart = a.imaginaryPart; return result; } 东南大学计算机学院 11/21/2018

33 两种运算符函数(11) 全局运算符函数不限制操作数的顺序 Complex a(1,1); double b = 2.0;
Complex c = a + b; //ok. c = operator+(a, b); Complex d = b + a; //ok c = operator+(b, a); class Complex{ friend Complex operator+(const Complex &, double); friend Complex operator+(double, const Complex &); private: double realPart; double imaginaryPart; }; Complex operator+(double b, const Complex & a) { return operator+(a, b); } 全局运算符函数不限制操作数的顺序

34 两种运算符函数比较 必须作为成员函数重载的运算符 必须作为全局函数重载的运算符 其他运算符可以作为成员函数或全局函数进行重载
()、[]、-> 任何赋值运算符 必须作为全局函数重载的运算符 流插入操作符(<<)和流提取运算符(>>) 可交换的运算符(指操作对象类型不同) 其他运算符可以作为成员函数或全局函数进行重载 用法一样,实现不同 东南大学计算机学院 11/21/2018

35 一元运算符重载(1) 成员运算符函数 全局运算符函数 non-static成员函数 没有参数 左操作数必须为本类对象 一般为友元函数
一个参数 参数必须是自定义类对象 + a a.operator+( ) operator+( a ) 东南大学计算机学院 11/21/2018

36 一元运算符重载(2) 判断String对象s是否为空字符串: 成员运算符重载 全局运算符重载 调用方式:s.operator!( )
class String { public: bool operator!() const; }; 调用方式:s.operator!( ) bool operator!( const String & ); 调用方式:operator!( s ) 东南大学计算机学院 11/21/2018

37 二元运算符重载(1) 成员运算符函数 全局运算符函数 一般为友元函数 non-static成员函数 两个参数 一个参数
左操作数必须为本类对象 一般为友元函数 两个参数 参数必须有一个自定义类对象 a + b a.operator+( b ) operator+(a, b) 东南大学计算机学院 11/21/2018

38 二元运算符重载(2) 判断String对象s1和s2是否相同: 成员运算符重载 全局运算符重载
class String { public: bool operator==(const String &) const; }; 调用方式:s1.operator==( s2 ) bool operator==(const String &, const String &); 调用方式:operator==( s1, s2 ) 东南大学计算机学院 11/21/2018

39 重载可交换的运算符(1) X 若两个操作对象是不同类型 成员运算符函数 左操作数不为本类对象 c = a + b c = b + a
A a, c; B b; 调用方式: c = a.operator+(b) c = b.operator+(a) X 左操作数不为本类对象 函数原型: class A{ public: A operator+(const B &); }; class B{ public: A operator+(const A &); }; 东南大学计算机学院 11/21/2018

40 重载可交换的运算符(2) 若两个操作对象是不同类型 全局运算符函数 重载可交换的运算符只能用全局运算符函数 c = a + b
c = b + a A a, c; B b; 调用方式: c = operator+(a, b) c = operator+(b, a) 函数原型: class A{ friend A operator+(const A &, const B &); friend A operator+(const B &, const A &); }; A operator+(const B & b, const A & a) { return operator+(a, b); } 重载可交换的运算符只能用全局运算符函数 东南大学计算机学院 11/21/2018

41 重载流插入/流提取运算符 东南大学计算机学院 11/21/2018

42   重载流插入符 成员运算符函数 全局运算符函数 cout是内置类型ostream类的对象
cout << a class A (chap15) 成员运算符函数 全局运算符函数 调用方式: cout.operator<<(a) cout是内置类型ostream类的对象 这意味着需要修改ostream类,这是不可能的 调用方式: operator<<(cout, a) 函数原型: 返回值类型 operator<<(ostream &, const A &) 只能以全局运算符函数重载流插入(<<)/提取操作符(>>) 东南大学计算机学院 11/21/2018

43 例子(1) Phone number的输入输出 格式: (800) 555-1212 重载方式 必须为全局运算符函数
能够级联调用:cout<<a<<b 函数返回值类型:ostream & code: Fig. 11.3~11.5 string areaCode; string exchange; string line; 数据成员: areaCode exchange line (800) cout<<a; cout<<b; How? 回顾:返回this指针 东南大学计算机学院 11/21/2018

44 例子(2) 重载流插入符<< cout << phone operator<<(cout, phone) class PhoneNumber { friend ostream & operator<<(ostream &, const PhoneNumber & ); } 不需改变phone的值,传const引用 ostream & operator<<( ostream &output, const PhoneNumber &number ) { output << "(" << number.areaCode << ") " << number.exchange << "-" << number.line; return output; } 从重载的流操作符返回的cin/cout等大部分stream对象一般是全局的,返回引用一般会成功,不会虚悬引用 东南大学计算机学院 11/21/2018

45 例子(3) 重载流提取符>> cin >> phone operator>>(cin, phone)
class PhoneNumber { friend istream & operator>>(istream &, PhoneNumber & ); } 需要改变phone的值,传引用 istream & operator>>( istream &input, PhoneNumber &number ) { input.ignore(); // skip ( input >> setw( 3 ) >> number.areaCode; // input area code input.ignore( 2 ); // skip ) and space input >> setw( 3 ) >> number.exchange; // input exchange input.ignore(); // skip dash (-) input >> setw( 4 ) >> number.line; // input line return input; // enables cin >> a >> b >> c; } setw()限定读到每个字符数组的个数

46 实例研究:Array类 基于指针的数组的缺点 Array类的功能 Array类实现 总结 东南大学计算机学院 11/21/2018

47 基于指针的数组的缺点 数组名是指向第一元素的const指针 缺点 下标必须是0,…,n-1 不能进行越界检查
不能对数组进行一次性输入/输出 只能针对单个元素分别进行 不能对两个数组进行有意义的比较运算(>, <, ==) 作为参数传递时,一般需要传递数组长度 不能使用赋值运算符(=)将一个数组赋值给另一个数组 int a[3]; a a[0] a[1] a[2] 数组名是const指针,不能用作左值 东南大学计算机学院 11/21/2018

48 扩展数组类 全局函数 Array类 重载<<和>>:实现数组整体的输入输出
重载赋值运算符=:将一个数组对象赋值给另一个数组 对象 重载关系运算符==:比较两个数组对象是否相同 重载关系运算符!=:比较两个数组对象是否不同 重载下标运算符[ ]: 可以进行越界检查 东南大学计算机学院 11/21/2018

49 Array类数据成员 class Array { …… private: int size; //数组长度
int *ptr; //数组名,指向第一个元素的地址 }; f(ptr, size) Array a; f(a); 东南大学计算机学院 11/21/2018

50 1.重载流插入/流提取符 class Array{
friend ostream & operator<<( ostream &, const Array & ); …… }; 必须用全局函数实现 不需改变a的值,传const引用 ostream &operator<<( ostream &output, const Array &a ){ int i; for ( i = 0; i < a.size; i++ ) { output << setw( 12 ) << a.ptr[ i ]; if ( ( i + 1 ) % 4 == 0 ) //每行4个元素 output << endl; } if ( i % 4 != 0 ) //最后一行回车 return output; // 级联调用,cout<<a<<b 5 6 7 东南大学计算机学院 11/21/2018

51 1.重载流插入/流提取符 class Array {
friend istream & operator>>( istream &, Array & ); …… }; 必须用全局函数实现 需要改变a的值,传引用 istream & operator>>( istream & input, Array & a ) { for ( int i = 0; i < a.size; i++ ) input >> a.ptr[ i ]; return input; // 级联调用, cin>>a>>b } 东南大学计算机学院 11/21/2018

52 2. 默认构造函数 构造特定长度的数组,默认值为10 Tips: 动态数组的管理 参数有效性判断 初始化:否则数组元素为随机数! 函数声明:
Array( int = 10 ); 18 Array::Array( int arraySize ) 19 { size = ( arraySize > 0 ? arraySize : 10 ); // 参数有效性 ptr = new int[ size ]; // 动态数组,运行时确定长度 22 for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; // 数组初始化 } 东南大学计算机学院 11/21/2018

53 3. 拷贝构造函数(1) 将一个数组中的函数拷贝到当前数组 Tips: 动态数组管理 初始化 函数声明:
Array( const Array & ); 参数为const引用,允许传入const实参 29 Array::Array( const Array &arrayToCopy ) : size( arrayToCopy.size ) 31 { ptr = new int[ size ]; // 动态数组,运行时确定长度 33 for ( int i = 0; i < size; i++ ) ptr[ i ] = arrayToCopy.ptr[ i ]; //拷贝数组元素 } 东南大学计算机学院 11/21/2018

54 3. 拷贝构造函数(2) 拷贝构造函数的作用? 与默认的逐个成员赋值的区别 何时调用拷贝构造函数?
通过建立一个现有对象的副本来初始化一个Array对象 默认的赋值运算符”=“不自动调用拷贝构造函数,执行默认的逐个成员赋值 默认的逐个成员赋值会使两个指针指向同一内存区域,易引 起虚悬指针! a.ptr b.ptr 需要创建对象副本时 按值传递参数时 (函数形参/函数返回值) 用对象的副本初始化另一对象时 Array a; Array b = a; //调用拷贝构造函数,而非赋值运算符函数 东南大学计算机学院 11/21/2018

55 东南大学计算机学院 11/21/2018

56 Array::Array(Array arrayToCopy )
3. 拷贝构造函数(3) 拷贝构造函数的参数类型为什么是const Array & ?可以 是Array 吗? const引用不需要拷贝const对象 不可以是Array,若为Array: Array::Array(Array arrayToCopy ) 需要创建实参的副本(拷贝),此时需要调用拷贝构造函数,即 该函数本身,造成无穷递归! 东南大学计算机学院 11/21/2018

57 4. 析构函数 Tips: 动态数组的内存释放 39 Array::~Array() 40 { 41 delete [] ptr; 42 }
40 { delete [] ptr; 42 } 东南大学计算机学院 11/21/2018

58 5. 重载运算符“=” Tips: 重载方式:必须为成员运算符函数 利用拷贝构造函数 使用: 函数声明: Array a;
Array b = a; b.operator=( a ); 函数声明: const Array &operator=( const Array & ) 右操作数a不改变,参数为const引用 左操作数b改变,不能为const函数 1. 为什么返回类型是const引用? 返回值类型指示赋值表达式的值的类型 const常量只能做右值,不能做左值 a = b = c是可以的,先执行b = c,再执行a = (b = c) 避免(a=b)=c. 东南大学计算机学院 11/21/2018

59 52 const Array &Array::operator=( const Array &right ) 53 {
53 { if ( &right != this ) //避免自我赋值 { //长度相等则直接拷贝 //不等则先释放原内存,再按长度申请新内存 if ( size != right.size ) { delete [] ptr; // release space size = right.size; // resize this object ptr = new int[ size ]; // create space for array copy } // end inner if 64 for ( int i = 0; i < size; i++ ) ptr[ i ] = right.ptr[ i ]; //拷贝 } // end outer if 68 return *this; //级联调用 a = b = c 70 } 2. 为什么要检测自我赋值? 若为自我赋值,则在赋值前,该对象的内存就被释放,导致致命的运行时错误 11/21/2018 东南大学计算机学院

60 6. 重载运算符“==”/“!=” Tips: 重载方式:成员运算符函数 利用已有函数 使用: 函数声明:
Array a(10), b(11); bool f = (a == b); bool g = (a!=b); f = a.operator==( b ); g = a.operator!=( b ); 函数声明: bool operator==( const Array & ) const bool operator!=( const Array & ) const 左/右操作数都不改变,参数为const引用,函数为const函数 11/21/2018 东南大学计算机学院

61 6. 重载运算符“==”/“!=” 24 bool operator!=( const Array &right ) const 25 {
74 bool Array::operator==( const Array &right ) const 75 { if ( size != right.size ) //首先判断长度是否相等 return false; //若不等,则返回false 78 for ( int i = 0; i < size; i++ ) //长度相等才判断数组元素是否都相同 if ( ptr[ i ] != right.ptr[ i ] ) return false; // 只要有一个元素不同,就返回false // 若遍历了整个数组都没有不同元素,就什么都不返回 return true; // 表明所有元素都相同,需要返回true 84 } 24 bool operator!=( const Array &right ) const 25 { return ! ( *this == right ); //利用已有函数 27 } 11/21/2018 东南大学计算机学院

62 7. 重载运算符“[]”(1) Tips: 重载方式:成员运算符函数 需要进行越界检查 使用: 函数声明: 返回左值,能被赋值
Array a(3); int b = a[2]; a[2] = 1; //ok b = a.operator[]( 2 ); a a[0] a[1] a[2] 需返回的地址 需要返回特定下标的数组元素地址 函数声明: int & operator[]( int ); 返回左值,能被赋值 11/21/2018 东南大学计算机学院

63 7. 重载运算符“[]”(2) 88 int &Array::operator[]( int subscript ) 89 {
89 { // 进行越界检查 if ( subscript < 0 || subscript >= size ) { cerr << "\nError: Subscript " << subscript << " out of range" << endl; exit( 1 ); //越界则退出程序 } 97 return ptr[ subscript ]; // 返回元素地址 99 } #include <cstdlib> using std::exit; 11/21/2018 东南大学计算机学院

64 7. 重载运算符“[]”(3) Tips: 要const版本的重载函数,以便const对象调用 (const对象只能调用const函数)
使用: const Array a(3); int b = a[2]; c [2] = 1; //error b = a.operator[]( 2 ); const版本函数 函数声明: int & operator[]( int ); 一般对象调用 int operator[]( int ) const; const对象调用 返回右值,不能被赋值 11/21/2018 东南大学计算机学院

65 7. 重载运算符“[]”(4) 103 int Array::operator[]( int subscript ) const 104 {
104 { // 进行越界检查 if ( subscript < 0 || subscript >= size ) { cerr << "\nError: Subscript " << subscript << " out of range" << endl; exit( 1 ); } 112 return ptr[ subscript ]; // 返回元素值 114 } 11/21/2018 东南大学计算机学院

66 总结(1) 关于动态内存管理 通常会为需要动态内存管理的类同时提供 若无拷贝构造函数和重载的赋值运算符 若无析构函数
拷贝构造函数(需要分配内存) 析构函数(需要释放内存) 重载的赋值运算符(需要删除原有内存并重新分配内存) 若无拷贝构造函数和重载的赋值运算符 执行操作:默认的逐个成员赋值 指向动态内存的指针指向同一地址,并造成内存泄漏 若无析构函数 不能自动释放动态内存区的变量 a.ptr b.ptr 东南大学计算机学院 11/21/2018

67 总结(2) 成员函数为private 重载的赋值运算符函数为private:阻止对象赋值 拷贝构造函数为private:阻止对象拷贝
无法调用默认的赋值运算函数,它被重载 无法调用默认的拷贝构造函数,它被重载 东南大学计算机学院 11/21/2018


Download ppt "刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 liuxy@seu.edu.cn http://cse.seu.edu.cn/people/xyliu/ 东南大学计算机学院."

Similar presentations


Ads by Google