C程序设计实验指导与题解.ppt_第1页
C程序设计实验指导与题解.ppt_第2页
C程序设计实验指导与题解.ppt_第3页
C程序设计实验指导与题解.ppt_第4页
C程序设计实验指导与题解.ppt_第5页
已阅读5页,还剩377页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C+程序设计 北京理工大学 计算机科学技术学院 赵清杰 2008.7 2 北京理工大学 计算机科学技术学院 2 C+程序设计 清华大学出版社,2008 3 北京理工大学 计算机科学技术学院 3 主要内容 第1章 C+语言概述 第2章 C+编程基础 第3章 函数与函数模板 第4章 类与类模板 第5章 运算符重载 第6章 继承与派生 第7章 多态 第8章 异常处理 第9章 C+标准库 4 北京理工大学 计算机科学技术学院 4 第1章 C+语言概述 5 北京理工大学 计算机科学技术学院 5 第1章 C+语言概述 本章简单介绍C+语言的特点以及 C+标准库的主要构成。 列举一个简单的C+程序。 程序的编辑、编译、连接与运行, 并介绍Visual C+ 6.0开发环境下 建立标准C+控制台应用程序的步 骤。 6 北京理工大学 计算机科学技术学院 6 第1章 C+语言概述 1.1 C+语言的特点 1.2 C+标准库简介 1.3 简单的C+程序 1.4 程序的编辑、编译、连接与运 行 1.5 小结 7 北京理工大学 计算机科学技术学院 7 1.1 C+语言的特点 支持过程式程序设计 procedural programming 支持基于对象的程序设计 object-based programming 支持面向对象的程序设计 object-oriented programming 支持泛型程序设计 generic programming C+是一门支持多种编程方法的程序设计语言: 8 北京理工大学 计算机科学技术学院 8 1.1 C+语言的特点 过程式程序设计通过一组算法建立问题的模型,程 序的构成就是“算法+数据”。C+能够兼容C语言, 但做了很多改进,例如对类型要求更加严格,输入 输出更方便,增加了新的运算符,允许函数和运算 符重载,增加了引用类型,提供inline、const等关 键字。总之,在支持过程式程序设计方面,比C语 言更安全、功能更强、使用更方便。 基于对象程序设计,主要特征是抽象和封装。它允 许将数据和操作封装在一起,形成抽象数据类型, 如类。把占据一块内存的类的实例称为该类型的对 象。基于对象的程序设计就是建立对象和通过公有 接口与对象联系的过程。 9 北京理工大学 计算机科学技术学院 9 1.1 C+语言的特点 抽象、封装、继承与多态是面向对象程序设计的主 要特征。在类与对象的基础上,C+通过继承和动 态绑定机制扩展了抽象数据类型。通过从基类派生 出子类,使用户无需修改原有的程序就可以重用已 有的资源,并能够进一步修改或增添功能。动态绑 定机制通过定义虚函数,使处于不同类层次的同名 函数,在程序运行时才被决定应该调用哪一个。 泛型程序设计,将算法从特定的数据类型中抽象出 来,使算法通用于不同的数据类型。泛型程序在代 码重用、组织性、可维护性以及效率等方面表现出 很强的优势。C+的模板语法机制,为范型程序设 计奠定了关键基础。 10 北京理工大学 计算机科学技术学院 10 第1章 C+语言概述 1.1 C+语言的特点 1.2 C+标准库简介 1.3 简单的C+程序 1.4 程序的编辑、编译、连接与运 行 1.5 小结 11 北京理工大学 计算机科学技术学院 11 1.2 C+标准库简介 C+标准库(Standard Library)定义了一些可供直 接使用的函数、类、对象等。这些定义分别放在不同 的头文件中,我们使用时只要包含相应的头文件即可 。 以前的C头文件和C+头文件名都是以“.h”做后缀的 ,如和。新的C+标准头文 件名不带后缀。以字母c开头的标准头文件(如 )等价于原来的C头文件。 标准头文件中定义的标识符(如类名、函数名、对象 名)都归属于名字空间std,使用时要加前缀“std:” 进行限制,或者使用using声明或using指令。 C+标准库主要包括流类、string、容器类、使用容 器的泛型算法、数值运算、C标准库、语言支持功能 等。 12 北京理工大学 计算机科学技术学院 12 1.2 C+标准库简介 图1-1 C+标准库构成 13 北京理工大学 计算机科学技术学院 13 1.2 C+标准库简介 C+(语言)与Visual C+(C+的开发环境) 我们要学习的是C+这门计算机语言的语法知识、 编程方法以及如何使用C+标准库。 不同企业的开发环境一般也为用户提供一个基础类 库,如Microsoft Visual C+的MFC(Microsoft Foundation Class Library),Borland C+ Builder的VCL(Visual Component Library)等 。软件开发人员也可以编写自己的类库。 本书我们只涉及C+标准库,而对不同的开发环境 及其类库不做具体介绍。 14 北京理工大学 计算机科学技术学院 14 第1章 C+语言概述 1.1 C+语言的特点 1.2 C+标准库简介 1.3 简单的C+程序 1.4 程序的编辑、编译、连接与运 行 1.5 小结 15 北京理工大学 计算机科学技术学院 15 1.3 简单的C+程序 /* /例1-1. 计算圆面积的C+程序 /数据描述:半径和面积均为实数 /数据处理:(a)从键盘输入半径r; /(b)计算面积=r2;(c)向屏幕输出半径和面积 /* 16 北京理工大学 计算机科学技术学院 16 1.3 简单的C+程序 17 北京理工大学 计算机科学技术学院 17 1.3 简单的C+程序 上述程序运行后,屏幕上显示: Please input radius: 如果我们从键盘输入: 3 屏幕上将显示: radius = 3 area = 28.2743 18 北京理工大学 计算机科学技术学院 18 1.3 简单的C+程序 例1-2. 数据的输出 # include using namespace std; int main() cout (Expr) const_cast(Expr) dynamic_cast(Expr) reinterpret_cast(Expr) 2. 显式转换 77 北京理工大学 计算机科学技术学院 77 2.2.5 类型转换 转换构造函数可以将某种类型的对 象转换成当前类类型。 类型转换函数可以将当前类型的对 象转换成指定的类型。 用户定义的转换 78 北京理工大学 计算机科学技术学院 78 2.2.6 typedef与typeid typedef可以为某种数据类型声明一 个新名字。 使用运算符typeid可以得到一个对象 的数据类型。 参见例2-15 79 北京理工大学 计算机科学技术学院 79 第2章 C+编程基础 2.1 C+的词法规则 2.2 C+的数据类型 2.3 表达式与语句 2.4 预处理命令 2.5 名字空间 2.6 小结 80 北京理工大学 计算机科学技术学院 80 2.3 表达式与语句 表达式由运算符和操作数组成,按 一定求值规则我们可以求出表达式 的值;其中操作数可以是常量、变 量或另一个表达式。 C+简单语句:表达式; 程序由语句组成。 81 北京理工大学 计算机科学技术学院 81 2.3 表达式与语句 2.3.1 运算符与表达式 算术运算符与表达式 关系运算符与表达式 逻辑运算符与表达式 位运算符与表达式 三元条件运算符与表达式 逗号运算符与表达式 动态内存分配与释放运算符 2.3.2 语句 简单语句,复合语句,控制语句(选择语 句、循环语句、跳转语句),判断表达式的 使用 82 北京理工大学 计算机科学技术学院 82 2.3.1 运算符与表达式 根据功能,运算符可分为算术运算符、关系运 算符、逻辑运算符、位运算符、赋值运算符及 特殊运算符。 根据所需操作数的个数,运算符可分为一元运 算符、二元运算符和三元运算符。一元运算符 只需要一个操作数,二元运算符需要两个操作 数,三元运算符则需要三个操作数,C+只有 一个三元运算符即“?:”。 一个表达式可以包含多个运算符,运算顺序由 各运算符的优先级和结合性决定。C+运算符 的功能和优先级参见表2-5。 83 北京理工大学 计算机科学技术学院 83 2.3.1 运算符与表达式 算术表达式由算术运算符和操作数组成,结果 是算术值,值的类型与操作数的类型有关。 普通算术运算符: 一元算术运算符:-(取负)、+(取正); 二元算术运算符:+、-、*、/、%(int型); 一元运算符优先级高于二元运算符; +和减-运算符 一元运算符,操作数必须是变量,分前缀和后缀 ; 优先级较高,结合性自右向左。 1. 算术运算符与表达式 84 北京理工大学 计算机科学技术学院 84 2.3.1 运算符与表达式 前缀“+”可以理解为“先增1后使用”,而前缀 “”可以理解为“先减1后使用”。 后缀“+”可以理解为“先使用后增1”,后缀“” 可以理解为“先使用后减1”。 int a1=1, c1=0; c1 = +a1;/a1=a1+1; c1=a1; int a2=1, c2=0; c2 = a2+;/c2=a2; a2=a2+1; 前缀方式与后缀方式的区别: 85 北京理工大学 计算机科学技术学院 85 2.3.1 运算符与表达式 关系表达式由关系运算符和操作数组成,用来 对两个操作数进行比较,结果为bool类型的值 。如果关系为真,则结果为true;如果关系为 假,则结果为false。 关系运算符包括:等于(=),不等于(!=) ,小于(), 大于等于(=)。后四种的优先级高于前两种 。 例如:设a=1, b=2,则表达式(ab)的值为false ,表达式(a)。“按位异或”运算的规则是:对应位 不同为1,相同为0。例如: unsigned int a = 8; /二进制为00001000 unsigned int c = a 10; /c=00000010 unsigned int b = a =)。例如: a = b = 5; /先将5赋给b,再赋给a a += 3; /等价于a=a+3 5. 赋值运算符与表达式 89 北京理工大学 计算机科学技术学院 89 2.3.1 运算符与表达式 C+唯一的一个三元运算符是“?:”,具有简单的 选择功能,其格式为: a1 ? a2 : a3 其中a1具有bool类型,a2和a3可以是任何类型 ,表达式的类型取决于a2和a3中类型高的一个。 上式的运算过程是,若a1为true则表达式值为a2 的值,否则表达式值为a3的值。例如求a和b中 较大的值,并将该值赋给c,结果c的值为5: int a=3, b=5, c=0; c = ( ab ) ? a : b; 6. 三元条件运算符与表达式 90 北京理工大学 计算机科学技术学院 90 2.3.1 运算符与表达式 逗号也是一个运算符,作用是将多个表达式连成 一个表达式。计算时从左至右计算每一个表达式 的值,逗号表达式的值与最后一个表达式的值相 同。例如: a = 2*3, a*5; /表达式相当于(a = 2*3), a*5 上述表达式中,逗号前面赋值表达式的值为6, a*5的值为30,则逗号表达式的值为30。 逗号运算符的优先级最低,使用较少。 7. 逗号运算符与表达式 91 北京理工大学 计算机科学技术学院 91 2.3.1 运算符与表达式 new运算符建立动态对象,并分配内存空间; delete运算符删除动态对象,即释放内存空间。 new和delete必须配对使用。 由new创建的堆对象没有名字,只能通过地址进 行访问,这一点与普通对象不同。例如: int* p1 = new int; int* p2 = new int(10); int* p3 = new int10; delete p1; delete p2; delete p3; 8. 动态内存分配与释放运算符 92 北京理工大学 计算机科学技术学院 92 2.3.2 语句 简单语句:空语句,定义语句,表达式语句 复合语句:多个简单语句用一对花括号括住 。 控制语句:可以改变程序的流程。包括 选择语句(if-else,switch) 循环语句(while,do-while,for) 跳转语句(break,continue,goto) 93 北京理工大学 计算机科学技术学院 93 2.3.2 语句 常用选择语句包括if-else 语句和switch语 句。 if-else 语句的两种形式(应用参见例2-16 ): 1. 选择语句 94 北京理工大学 计算机科学技术学院 94 2.3.2 语句 if-else语句嵌套使用可以实现多路分支,但 比较繁琐,而用switch语句比较简单。语法 : 1. 选择语句 switch (表达式) case常量表达式1: 语句1; break; case常量表达式2: 语句2; break; case常量表达式n: 语句n; break; default: 语句n+1; 95 北京理工大学 计算机科学技术学院 95 2.3.2 语句 C+中可使用三种循环语句:while循环、 do-while循环和for循环。 while循环: while (表达式) 循环体 参见例2-17 2. 循环语句 96 北京理工大学 计算机科学技术学院 96 2.3.2 语句 do-while循环: do 循环体 while (表达式); 2. 循环语句 97 北京理工大学 计算机科学技术学院 97 2.3.2 语句 for循环: for ( 表达式1; 表达式2; 表达式3 ) 循环体 参见例2-18。 2. 循环语句 98 北京理工大学 计算机科学技术学院 98 2.3.2 语句 跳转语句包括break语句、continue语句 和goto语句。由于goto语句存在较大的 安全隐患,尽量不用。 break语句可用于switch和循环结构中, 作用是退出switch或循环体。 continue语句一般只能用于循环结构中 ,作用是结束本次循环,进入下一次循环 。 参见例2-19。 3. 跳转语句 99 北京理工大学 计算机科学技术学院 99 2.3.2 语句 在C+中,当表达式值为非0,被认为是true;只 有当表达式的值等于0时,才认为是false。 利用C+表达式的灵活性,可以简化代码。如果 表达式expr的值为布尔型、整型、指针值等 ,与0比较时都可以采用下列方式: expr 相当于expression != 0 !expr相当于expression = 0 if( a-b ) 相当于 if( (a-b) != 0 ) while( p /函数声明 double d = 0.8; /全局变量定义 #endif / HEAD1_H 109 北京理工大学 计算机科学技术学院 109 第2章 C+编程基础 2.1 C+的词法规则 2.2 C+的数据类型 2.3 表达式与语句 2.4 预处理命令 2.5 名字空间 2.6 小结 110 北京理工大学 计算机科学技术学院 110 2.5 名字空间 虽然标识符可以具有函数域、类域,可以通 过static使函数和对象具有文件域,但全局性 的对象名、函数名以及类名还在同一个全局 名字空间中。一个大型软件往往由多人完成 ,一旦对全局性的名字缺乏控制就会出现名 字冲突。 名字空间(namespace)是C+的新特性之 一。可以把来自不同编程人员的全局性标识 符归属不同的名字空间,从而解决程序开发 中常见的同名冲突问题。 111 北京理工大学 计算机科学技术学院 111 2.5.1 名字空间声明 下面的代码声明对象d、函数Print和类X属于名字 空间calculator,其中“namespace”是关键字, “calculator”是名字空间的名字。 namespace calculator double d = 0.5; void Print(double x) cout using namespace std; namespace calculator /名字空间定义 double d = 0.5; void Print(double x) cout int main( ) std:cout using namespace std; /打开名字空间 std int main( ) cout 中进行了说明,使用时用#include将该头 文件嵌入即可。参见例3-10。 137 北京理工大学 计算机科学技术学院 137 第3章 函数与函数模板 3.1 函数的定义与声明 3.2 函数调用 3.3 函数指针 3.4 static函数 3.5 inline函数 3.6 函数重载 3.7 带默认形参值的函数 3.8 函数模板 3.9 小结 138 北京理工大学 计算机科学技术学院 138 3.3 函数指针 函数的语句序列经过编译之后,转化成二进制代码 并存入内存,每个函数模块对应一个起始地址,称 为函数的入口地址。函数名就代表一个函数的起始 地址。 也可以用一个指向函数的指针来存放函数的起始地 址,并通过该指针调用函数。这种指针称为指向函 数的指针,简称函数指针。例如: double add(double x, double y) return (x+y) ; double ( *fp )( double x, double y ) = add; / 定义 fp(1.2, 2.0); /通过函数指针调用函数 139 北京理工大学 计算机科学技术学院 139 3.3 函数指针 上面通过指针调用函数的写法,表面看来与通过函 数名调用函数的写法一样。不同的是,fp是一个变 量,它可以重新指向其他相匹配的函数;而add相 当于一个常量,它所代表的函数入口地址是固定的 。 函数(或函数指针)可以作为另一个函数的参数。 参见例3-11。fun()的第2个参数类型为函数,调用 函数fun()进行参数传递时,同样要分析实参和形 参的类型是否匹配。由于第2个参数是函数类型, 则被调用的函数参数表与返回类型要与形参的函数 类型匹配。 140 北京理工大学 计算机科学技术学院 140 第3章 函数与函数模板 3.1 函数的定义与声明 3.2 函数调用 3.3 函数指针 3.4 static函数 3.5 inline函数 3.6 函数重载 3.7 带默认形参值的函数 3.8 函数模板 3.9 小结 141 北京理工大学 计算机科学技术学院 141 3.4 static函数 对于多个文件程序,一般在类体外定 义的函数,在整个程序的任意位置都 可以调用。 如果只允许在一个编译单元内使用某 个函数,可以在函数定义时加static约 束。 参见例3-12。 142 北京理工大学 计算机科学技术学院 142 第3章 函数与函数模板 3.1 函数的定义与声明 3.2 函数调用 3.3 函数指针 3.4 static函数 3.5 inline函数 3.6 函数重载 3.7 带默认形参值的函数 3.8 函数模板 3.9 小结 143 北京理工大学 计算机科学技术学院 143 3.5 inline函数 函数调用时,需要保存现场状态,进行参 数传递,现场恢复等。对于一个小操作来 说,也许函数调用前后所做的工作比执行 函数体内的代码要复杂得多。 为了提高程序的运行效率,可以将功能简 单、代码较短、使用频繁的函数,声明为 inline,编译时将函数体嵌入函数调用处 。 参见例3-13。 144 北京理工大学 计算机科学技术学院 144 3.5 inline函数 inline函数适用于只有几行的简单小程序。inline函 数的定义应出现在被调用之前,并且在调用该函数的 每个文本文件中都要进行定义。 inline只是表示一种要求,编译器并非将inline修饰 的函数一定作为内嵌处理。 类体内定义的函数即使不带inline关键字,也是 inline函数。 使用inline函数可以节省运行时间,但程序的目标代 码量增加。 inline函数与带参数的宏具有相似的功能,但后者存 在安全问题,建议不用。 145 北京理工大学 计算机科学技术学院 145 /使用带参数的宏 #include using namespace std; #define f(x) x*x int main() int x = 2; cout using namespace std; inline int f(int x) return x*x; int main() int x = 2; cout using namespace std; template /T为类型参数 T add( T x, T y ) return (x+y); int main( ) double d1=0.5, d2=8.8; cout (2, 3) cout ( d1, d2) return 0; 156 北京理工大学 计算机科学技术学院 156 3.8.1 函数模板的定义与使用 函数模板并不是一个真正的函数。程序编译时,编译 器根据调用语句中的实参类型对函数模板实例化,生 成一个具体的可运行的函数。例如,编译add(2, 3) 时,编译器发现2和3是int型,于是使用如下版本的 函数: int add(int x, int y ) return (x+y); 编译add(d1, d2)时,编译器发现d1和d2是double型 ,于是使用如下版本的函数: double add(double x, double y ) return (x+y); 函数模板的形参列表中也可以带其他类型的参数。参 见例3-16和例3-17。 157 北京理工大学 计算机科学技术学院 157 3.8.2 函数模板重载 函数模板也可以重载 。参见例3-18。 编译器通过匹配过程,可以正确决定应该调 用哪个函数形式。 当程序中同时重载有函数模板和非模板函数 时,编译器会优先选用非模板函数,当然前 提是类型最佳匹配。如果一个调用有多于一 个的匹配选择,则说明函数或函数模板在定 义时存在歧义,编译时将会出错。 158 北京理工大学 计算机科学技术学院 158 3.8.3 函数模板专门化 使用函数模板,编译器会根据实参类型自动将模板 实例化,即用具体的数据类型代替类型参数。 C+也提供一种将模板显性专门化的语法。即定义 函数时,使用前缀“template0?x1:x2; “template ”的目的是告诉编译器,当数据类型 为char*时选用专门化的定义形式。其中函数名后 面可以省略。参见例3-19。 159 北京理工大学 计算机科学技术学院 159 3.8.4 使用标准库中的函数模板 C+标准库中的算法函数基本上都是模板, 适用于数组等容器类型,编程时可以直接使 用,但要#include相应的头文件。主要的头 文件有、 、等。 例3-20演示如何使用标准库中定义的泛型函 数,进行数组元素排序、复制、输出等操作 。 160 北京理工大学 计算机科学技术学院 160 第3章 函数与函数模板 3.1 函数的定义与声明 3.2 函数调用 3.3 函数指针 3.4 static函数 3.5 inline函数 3.6 函数重载 3.7 带默认形参值的函数 3.8 函数模板 3.9 小结 161 北京理工大学 计算机科学技术学院 161 3.9 小结 函数是程序功能划分和代码重用的主要手段之一。 主函数是程序执行的开始点,主函数内可以调用子 函数,子函数内还可以继续调用其他子函数。 函数的参数与返回类型是函数与外部通信的接口。 函数可以返回一个值或地址。函数参数类型可以是 C+允许的任意数据类型。参数传递方式包括值传 递和地址传递。 函数名代表函数的入口地址。 可以用函数指针来存放函数的起始地址,并通过函 数指针调用函数。 162 北京理工大学 计算机科学技术学院 162 3.9 小结 static函数只在定义它的编译单元内可用。 inline函数可以提高程序的运行效率。 在定义或声明函数时,可以为形参指定默认值。 C+允许同一作用域内重载同名函数。 C+的模板机制为泛型编程打下了很好的基础。模 板包括函数模板和类模板。 定义函数模板时,函数的返回类型和形参类型不具 体指定,而用抽象的类型参数来表示。调用时再用 具体的数据类型代替抽象的类型参数。 函数模板可以重载。 163 北京理工大学 计算机科学技术学院 163 第4章 类与类模板 164 北京理工大学 计算机科学技术学院 164 第4章 类与类模板 类是基于对象和面向对象程序设计的基 础。 类将不同类型的数据以及对数据的操作 封装起来,形成高度抽象的数据类型。 数据抽象及封装是面向对象程序设计的 基本特征之一。 本章主要介绍类与类对象的定义,详细 讨论类的构造函数与析构函数,特别是 构造函数的不同重载形式。介绍赋值成 员函数,static成员及const成员,指向 成员的指针,以及组合类、友元,类模 板的定义、专门化等内容。 165 北京理工大学 计算机科学技术学院 165 第4章 类与类模板 4.1 类与类对象的定义 4.2 构造函数与析构函数 4.3 赋值成员函数 4.4 静态成员 4.5 常成员 4.6 指向成员的指针 4.7 组合类 4.8 友元 4.9 类模板 4.10 小结 166 北京理工大学 计算机科学技术学院 166 4.1.1 类的定义 定义一个类,实际上就是定义一种新 的数据类型。 类把数据和操作封装在一起,其中的 数据成员和成员函数统称为类的成员 。 在定义类时还要对类中的某些成员进 行隐藏,因此类不仅具有封装性,还 具有信息隐藏性。 167 北京理工大学 计算机科学技术学院 167 4.1.1 类的定义 类定义的一般形式: class 类名 public: 公有的数据成员和成员函 数; protected: 受保护的数据成员和成员 函数; private: 私有的数据成员和成员函 数; ; /此处的分号不能少! 168 北京理工大学 计算机科学技术学院 168 4.1.1 类的定义 public、private以及protected是访问属性关键字, 它们控制外界访问类成员的权限。成员的默认访问 属性为private。 一般成员函数和友元函数可以访问本类的所有成员 。 外界可以访问类对象的公有成员,公有成员为类与 外界交互的接口。一般将成员函数声明为类的公有 成员。 外界不能访问类的私有成员。私有成员是类中被隐 藏的部分。一般将数据成员定义为类的私有成员。 受保护成员具有和私有成员相似的访问属性,但在 多层次继承的情况下,基类受保护成员在派生类中 的访问属性与私有成员有所不同,第6章介绍。 169 北京理工大学 计算机科学技术学院 169 4.1.1 类的定义 class CPoint public: int Xcoord() return X; /成员函数定义 int Ycoord() return Y; /成员函数定义 void SetPoint( int x, int y ) X = x; Y = y; void Move( int dx, int dy ) X += dx; Y += dy; private: int X, Y; /数据成员 ; /此处分号不能少! 170 北京理工大学 计算机科学技术学院 170 4.1.1 类的定义 class CPoint public: int Xcoord() return X; /成员函数定义 int Ycoord() return Y; /成员函数定义 void SetPoint( int x, int y ) X = x; Y = y; void Move( int dx, int dy ) X += dx; Y += dy; private: int X, Y; /数据成员 ; /此处分号不能少! 171 北京理工大学 计算机科学技术学院 171 4.1.1 类的定义 成员函数的函数体部分(实现部分)可以在类内, 也可以在类外。当成员函数的定义放在类体外时, 必须在类体内对函数进行声明,类外定义时应在函 数名前加上类名和作用域限定符“:”。 类体内定义的成员函数默认为inline函数。类体外定 义的成员函数默认情况下不是inline,但可以声明它 为inline,只需在函数声明以及函数定义的开始加上 关键字inline即可。注意这时应将定义类和定义成员 函数的源代码放在同一个文件中,否则编译时在函 数调用处无法进行代码置换。参见例4-1。 一般成员函数可以重载,参数可以带有默认值。但 是析构函数不带参数,不能重载。 172 北京理工大学 计算机科学技术学院 172 4.1.2 类对象 类对象的定义形式和基本数据类型对象一 样。例如: int a1, a2, a3; /int对象a1、a2和数组a int* pi = /指向int对象的指针 int /int对象a1的一个引用ar CPoint c1, c2, c3; /CPoint型 CPoint* pc = /指向CPoint对象的 指针 CPoint /CPoint型对象c1的 引用 1. 类对象的定义 173 北京理工大学 计算机科学技术学院 173 4.1.2 类对象 类代表了某类对象的共同特征,类对象是类的实例 (instance。一个类的多个对象分别拥有自己的一 套数据成员和成员函数。 可以通过对象名(使用运算符“.” )或指向对象的指 针(使用运算符“-”)来访问对象的成员。 类的所有非静态成员函数都有隐含一个this指针参 数。当建立类对象时,this就自动被初始化指向该 对象。 参见例4-2 。 利用指向数据成员和成员函数的指针,4.6节介绍。 2. 如何访问类对象的成员 174 北京理工大学 计算机科学技术学院 174 4.1.2 类对象 每个对象所占用的存储空间只是该对象数据部分所 占用的存储空间,而不包括函数代码部分。 同类成员函数的代码在内存中只有一份拷贝。但是 调用一个对象的成员函数与调用另一个对象的相同 成员函数,传递的参数和执行的结果是不一样的。 3. 类对象的存储 175 北京理工大学 计算机科学技术学院 175 4.1.3 类的封装性和信息隐藏 把数据和操作数据的算法封装在一起。外界只 能通过公有接口实现对数据的访问,而不能直 接访问私有的数据,这就起到了信息隐藏的作 用。 将类的接口与实现分离。对于类的用户来说, 只需要知道类的接口、而不需要知道类的实现 细节,这样既保证了程序的安全,又保护了开 发者的权益。参见例4-3。 教材中的例子大都比较短小,多数情况下将所 有代码都放在一个cpp文件中。 176 北京理工大学 计算机科学技术学院 176 第4章 类与类模板 4.1 类与类对象的定义 4.2 构造函数与析构函数 4.3 赋值成员函数 4.4 静态成员 4.5 常成员 4.6 指向成员的指针 4.7 组合类 4.8 友元 4.9 类模板 4.10 小结 177 北京理工大学 计算机科学技术学院 177 4.2 构造函数与析构函数 类对象的初始化工作是通过自动调 用构造函数完成的。当对象完成使 命后,再自动调用析构函数从内存 删除对象。 构造函数和析构函数都是特殊的成 员函数。 178 北京理工大学 计算机科学技术学院 178 4.2.1 构造函数 1. 构造函数的定义与作用 2. 带参数的构造函数 3. 成员初始化列表 4. 构造函数的重载 5. 带默认参数值的构造函数 6. 拷贝构造函数 7. 转换构造函数 179 北京理工大学 计算机科学技术学院 179 4.2.1 构造函数 当建立类的对象时,构造函数自动被调用 。 构造函数的名字与类的名字相同,不带返 回类型(注意不是void)。用户可以根据 初始化的要求设计构造函数的参数和函数 体。 带构造函数的CPoint类定义参见例4-4 , 作用是建立类对象时对两个int数据成员X 和Y初始化。 1. 构造函数的定义与作用 180 北京理工大学 计算机科学技术学院 180 4.2.1 构造函数 构造函数的主要功能是初始化数据成员,函数体 内也可以有其他功能的语句,但最后不含与初始 化无关的操作,以保持程序的清晰。 构造函数也可以定义在类体外,其函数名前同样 要加上“类名:”。 构造函数由系统自动调用,用户不能随意调用。 任何一个类都必须含有构造函数,如果类的设计 者没有定义构造函数,则系统会自动生成一个不 带参数的构造函数,它只负责创建对象,而不做 初始化工作。 1. 构造函数的定义与作用 181 北京理工大学 计算机科学技术学院 181 4.2.1 构造函数 带参数的构造函数,可以将不同的实参数 值传递给构造函数,从而实现不同的初始 化。 在建立对象时给出实参值,在自动调用构 造函数的同时将实参值传递给构造函数, 参数值传递的顺序与一般函数一样是从左 到右。参见例4-5。 2. 带参数的构造函数 182 北京理工大学 计算机科学技术学院 182 4.2.1 构造函数 前面是在构造函数的函数体内对数据成员赋以初值 。也可以在成员初始化列表中初始化,有的数据成 员则要求必须在列表中初始化。例4-4中CPoint构 造函数的定义可写为: CPoint(int x, int y): X(x), Y(y) 调用构造函数时先执行成员初始化列表,再按顺序 执行花括号内的语句。数据成员在初始化列表中的 初始化顺序,与它们在类中的声明顺序有关,而与 它们在初始化列表中给出的顺序无关。 如果构造函数在类体外定义,那么初始化列表在函 数定义中给出。参见例4-6。 3. 构造函数的成员初始化列表 183 北京理工大学 计算机科学技术学院 183 4.2.1 构造函数 构造函数可以被重载, 以提供类对象的不 同初始化方法。参见例4-7。 创建类对象时,如果找不到相匹配的构造 函数,那么就不能建立相应的对象。 4. 构造函数的重载 184 北京理工大学 计算机科学技术学院 184 4.2.1 构造函数 函数重载增加了源代码量。可以使用带默认参数值 的构造函数。例如: CPoint(int x=0, int y=0) X=x; Y=y; 构造函数参数传递时,顺序是从左到右。如果给出 了实参值,则对应的数据成员采用实参值作为初值 ,否则采用默认参数值作为初值。参见例4-8。 如果构造函数在类体之外定义,那么应该在类内声 明构造函数时为参数指定默认值。 一般要避免同时使用带默认参数值的构造函数和重 载构造函数,否则容易出现歧义性问题。 5. 带默认参数值的构造函数 185 北京理工大学 计算机科学技术学院 185 4.2.1 构造函数 有时我们希望像基本数据类型那样,利用已有 的类对象去初始化新创建的类对象。例如: int a1 = 0; int a2(a1); CPoint obj1; CPoint obj2(obj1); 类对象的这种初始化方式是通过调用拷贝初始 化构造函数(简称拷贝构造函数)实现的。 6. 拷贝构造函数 186 北京理工大学 计算机科学技术学院 186 4.2.1 构造函数 每一个类都必须含有拷贝构造函数,如果设计人员 没有显性定义,编译器会自动生成一个默认的拷贝 构造函数。 拷贝构造函数也是构造函数,它的形参类型是类类 型的引用,这样在参数传递时就不用建立新的类对 象,而只是对实参的引用。为了保证不修改被引用 的对象,通常把引用参数声明为const。参见例4-9 。 在函数参数传递(参数为类类型)、函数值返回(返回 类类型)时也会调用拷贝构造函数。参见例4-10。 有时利用系统自动生成的拷贝构造函数可以满足要 求, 但有时需要自己定义,具体我们后面会遇到。 6. 拷贝构造函数 187 北京理工大学 计算机科学技术学院 187 4.2.1 构造函数 利用转换构造函数可以将指定的数据类型转换 为当前的类类型。例如由int转换为CPoint。 转换构造函数实际上是带默认参数值的构造函 数。如果构造函数的参数从第2个开始都带有默 认值,那么该构造函数就可以将第1个参数的类 型自动转换为当前的类类型。假设下列构造函 数: CPoint: CPoint ( int r) X=r; Y=0; 那么语句“CPoint(5);”的功能是:调用转换构造 函数将5转换为CPoint类型。本质上是建立一个 类对象,数据成员初值分别为5和0。 7. 转换构造函数 188 北京理工大学 计算机科学技术学院 188 4.2.1 构造函数 调用转换构造函数时,要建立一个匿名的临时 对象,该对象使用完毕后被自动删除。 对类型转换运算符“()”进行重载,可以实现将类 类型转换为其他类型。具体见下一章内容。 转换构造函数和类型转换运算符,都是在需要 时由系统自动调用。 注意4.2.1节几种构造函数形式,是指构造函数 的不同重载形式。在建立类对象需要调用构造 函数时,系统会根据情况调用其中的一个。 7. 转换构造函数 189 北京理工大学 计算机科学技术学院 189 4.2.2 析构函数 析构函数从内存中删除类对象。 析构函数的名字是类名前加符号“”。析构函数 不带参数,不能重载,也没有返回类型。其定 义形式如下: CPoint:CPoint() 每一个类都必须有析构函数,如果设计者没有 定义,则C+系统会自动生成一个默认的析构 函数,函数体内为空。 析构函数也是由系统自动调用的,用户不能随 意调用。 190 北京理工大学 计算机科学技术学院 190 4.2.2 析构函数 class Student public: Student ()/构造函数定义 number = 200801; name = new char20; /申请堆空间 Student() delete name; /析构函数定义 private: long int number; char* name; /指针型数据成员 ; 191 北京理工大学 计算机科学技术学院 191 4.2.3 构造与析构的顺序 在同样的作用域内,调用构造函数建立类对象的顺 序是谁的定义在前谁先建立;而调用析构函数删除 类对象的顺序与构造的顺序正好相反。 调用函数进行参数传递时,会建立局部的参数对象 ,虽然参数信息传递的顺序是从左向右,但参数对 象建立的顺序是从右向左。参见例4-11。 当全局对象、静态局部对象、一般局部对象都存在 的情况下,自动析构顺序一般是:先删除一般局部 对象,其次是静态局部对象,最后删除全局对象。 用new建立的堆对象,只能通过delete删除。函数 内定义的非静态对象,当这个函数被调用结束时删 除。参见例4-12。 192 北京理工大学 计算机科学技术学院 192 第4章 类与类模板 4.1 类与类对象的定义 4.2 构造函数与析构函数 4.3 赋值成员函数 4.4 静态成员 4.5 常成员 4.6 指向成员的指针 4.7 组合类 4.8 友元 4.9 类模板 4.10 小结 193 北京理工大学 计算机科学技术学院 193 4.3 赋值成员函数 拷贝构造函数的作用是:利用已有类对象去初始化 新建的类对象。我们也希望类对象能够像基本数据 类型的变量那样可以相互赋值。例如: int a1=0, a2=0; a2 = a1; CPoint obj1, obj2; obj2 = obj1; 类对象的这种赋值方式是通过重载赋值运算符函数 operator=()实现的, 该运算符必须重载为类的成员 ,简称赋值函数。 每一个类都必须含有赋值函数,如果设计人员没有 显性定义,编译器会自动生成一个。 194 北京理工大学 计算机科学技术学院 194 4.3 赋值成员函数 赋值函数的返回类型和形参类型是类类型的引用, 为了保证不修改被引用的对象,通常把引用参数声 明为const。例如: CPoint/用被引用对象的X值修改当前对象 的X Y = ref.Y ;/用被引用对象的Y值修改当前对象 的Y Return *this ;/返回当前对象 赋值函数和拷贝构造函数的实现非常相似。不同的 是,赋值函数返回*this,以符合赋值的本来含义 。拷贝构造函数用于对象的初始化,而赋值函数用 于修改类对象的值。 195 北京理工大学 计算机科学技术学院 195 4.3 赋值成员函数 一旦定义了赋值函数,就可以像基本数据类 型对象那样使用赋值符号“=”。例如: CPoint obj1, obj2, obj3; /建立三个 类对象 obj3 = obj2 = obj1; 上面的赋值操作,实际上是把obj1作为实参 ,先调用对象obj2的赋值函数即 “obj2.operator= (obj1);”,然后把返回值 作为实参,再调用对象obj3的赋值函数。 参见例4-13。 196 北京理工大学 计算机科学技术学院 196 4.3 赋值成员函数 有时用户必须自己定义拷贝构造函数和赋值函数, 例如类中包含指向动态分配内存的指针成员的情况 。 class A public: A(int r) p = new int(r); /初始化p指向int 对象 A(

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论