C程序设计(谭浩强完整版)改.ppt
《C程序设计(谭浩强完整版)改.ppt》由会员分享,可在线阅读,更多相关《C程序设计(谭浩强完整版)改.ppt(309页珍藏版)》请在装配图网上搜索。
1 includevoidmain void charc1 c2 c3 c4 charn1 n2 c1 a 字符常量c2 97 十进制c3 x61 转义字符c4 0141 八进制cout c1 c1 t c2 c2 endl cout c3 c3 t c4 c4 endl n1 n 转义字符 回车n2 t 转义字符 下一个输出区 Tab cout 使用转义字符 n cout c1 c1 n2 c2 c2 n1 cout c3 c3 n2 c4 c4 n1 输出 c1 ac2 ac3 ac4 a使用转义字符c1 ac2 ac3 ac4 a 2 标识符常量在C 中有二种方法定义标识符常量 一种是使用编译预处理指令 另一种是使用C 的常量说明符const constfloatpi 3 1415926 将变量pi定义为常量 举例说明 3 include definePI3 14156 defineS China voidmain void constfloatpi 3 14156 变量作为常量使用cout PI PI endl cout 10 PI 10 PI endl cout S endl cout PI PI endl cout pi pi endl 输出 PI 3 1415610 PI 31 4156ChinaPI 3 14156pi 3 14156 4 两个整数相除结果为整数1 2 05 2 2 整数才可求余 余数的符号与左边数的符号相同 3 2 1 3 2 13 2 1 3 2 18 4 0 5 输入语句 cin 程序在执行期间 接收外部信息的操作称为程序的输入 而把程序向外部发送信息的操作称为程序的输出 在C 中没有专门的输入输出语句 所有输入输出是通过输入输出流来实现的 6 要使用C 提供的输入输出时 必须在程序的开头增加一行 include即包含输入输出流的头文件 iostream h 7 输入十进制整数和实数 cin 举例说明 inta b cin a b 程序运行至此停下 等待从键盘输入变量值 键盘输入 35或 35均可 输入语句自动过滤空白字符 8 浮点型数据同整型数据一样 floatc d cin c d charch1 ch2 cin ch1 ch2 若输入 ab则ch1为a ch2为b 若输入 ab则ch1为a ch2为b 字符型变量过滤空白字符 cin格式过滤空白字符 9 floata inti1 i2 charch1 ch2 cin i1 a i2 ch1 ch2 输入 345 6781ab i2 1 在缺省的情况下 cin自动跳过输入的空格 换言之 cin不能将输入的空格赋给字符型变量 同样地 回车键也是作为输入字符之间的分隔符 也不能将输入的回车键字符赋给字符型变量 a 5 578 i1 34 ch1 a ch2 b 10 若要把从键盘上输入的每一个字符 包括空格和回车键都作为一个输入字符赋给字符型变量时 必须使用函数cin get 其格式为 cin get cin get 从输入行中取出一个字符 并将它赋给字符型变量 这个语句一次只能从输入行中提取一个字符 charc1 cin get c1 11 charch1 ch2 ch3 cin get ch1 cin get ch2 cin get ch3 输入 AB 则 ch1 A ch2 空格 ch3 B 12 输入十六进制或八进制数据 在缺省的情况下 系统约定输入的整型数是十进制数据 当要求按八进制或十六进制输入数据时 在cin中必须指明相应的数据类型 hex为十六进制 oct为八进制 dec为十进制 13 inti j k l cin hex i 指明输入为十六进制数cin oct j 指明输入为八进制数cin k 输入仍为八进制数cin dec l 指明输入为十进制数当执行到语句cin时 若输入的数据为 11111212 结果 i 17 j 9 k 10 l 12 14 使用非十进制数输入时 要注意以下几点 1 八进制或十六进制数的输入 只能适用于整型变量 不适用于字符型变量 实型变量 2 当在cin中指明使用的数制输入后 则所指明的数制一直有效 直到在接着的cin中指明输入时所使用的另一数制为止 如上例中 输入k的值时 仍为八进制 15 3 输入数据的格式 个数和类型必须与cin中所列举的变量类型一一对应 一旦输入出错 不仅使当前的输入数据不正确 而且使得后面的提取数据也不正确 cin a b cin ab cin ab inta b cin a b 16 输出数据cout与输入cin对应的输出是cout输出流 当要输出一个表达式的值时 可使用cout来实现 其一般格式为 cout 其中运算符 称为插入运算符 它将紧跟其后的表达式的值 输出到显示器当前光标的位置 17 inta 6 floatf1 12 4 chars1 abcd cout a t f1 t s1 endl t 为转义字符Tabendl为回车或 n 6 12 4 abcd 18 cout将双引号中的字符串常量按其原样输出 charch1 a ch2 b cout c1 ch1 t c2 ch2 endl c1 ac2 b inti1 4 i2 5 floata 3 5 cout a i1 a i1 endl a i2 a i2 endl a i1 14a i2 17 5 19 指定输出项占用的宽度 在输出的数据项之间进行隔开的另一种办法是指定输出项的宽度 如上面的两个输出语句可改写为 cout setw 6 i setw 10 j endl 4 12 cout setw 5 m setw 10 j k endl 7 24 其中setw 6 指明其后的输出项占用的字符宽度为6 即括号中的值指出紧跟其后的输出项占用的字符位置个数 并向右对齐 setw是 setwidth 的缩写 20 使用setw 应注意以下三点 1 在程序的开始位置必须包含头文件iomanip h 即在程序的开头增加 include 2 括号中必须给出一个表达式 值为正整数 它指明紧跟其后输出项的宽度 3 该设置仅对其后的一个输出项有效 一旦按指定的宽度输出其后的输出项后 又回到原来的缺省输出方式 21 引用 对变量起另外一个名字 外号 这个名字称为该变量的引用 其中原变量名必须是一个已定义过的变量 如 intmax int refmax并没有重新在内存中开辟单元 只是引用max的单元 max与refmax在内存中占用同一地址 即同一地址两个名字 22 max refmax 5 10 intmax int max 5 20 refmax 10 refmax max refmax max与refmax同一地址 23 对引用类型的变量 说明以下几点 1 引用在定义的时候要初始化 2 对引用的操作就是对被引用的变量的操作 int int 错误 没有具体的引用对象 max是已定义过的变量 3 引用类型变量的初始化值不能是一个常数 如 int 24 4 引用同变量一样有地址 可以对其地址进行操作 即将其地址赋给一指针 inta p int a p m 10 p m 是变量的引用 是变量的地址 25 5 可以用动态分配的内存空间来初始化一个引用变量 float 收回这个空间这个空间只有别名 但程序可以引用到 26 指针与引用的区别 1 指针是通过地址间接访问某个变量 而引用是通过别名直接访问某个变量 2 引用必须初始化 而一旦被初始化后不得再作为其它变量的别名 27 当 a的前面有类型符时 如int a 它必然是对引用的声明 如果前面无类型符 如cout a 则是取变量的地址 28 voidmain void constint 对常量 用const声明 的引用 29 引用与函数 引用的用途主要是用来作函数的参数或函数的返回值 引用作函数的形参 实际上是在被调函数中对实参变量进行操作 voidchange int a 3 b 5 x y t 3 5 3 输出 53 30 引用作为形参 实参是变量而不是地址 这与指针变量作形参不一样 voidchange int voidchange int x int y intt t x x y y z voidmain void inta 3 b 5 change 形参为整型引用 形参为指针变量 a 3 b 5 x y t a b 3 5 3 31 函数的返回值为引用类型 可以把函数定义为引用类型 这时函数的返回值即为某一变量的引用 别名 因此 它相当于返回了一个变量 所以可对其返回值进行赋值操作 这一点类同于函数的返回值为指针类型 32 每一个实体都是对象 有一些对象是具有相同的结构和特性的 每个对象都属于一个特定的类型 在C 中对象的类型称为类 class 类代表了某一批对象的共性和特征 类是对象的抽象 而对象是类的具体实例 instance 33 类是一种复杂的数据类型 它是将不同类型的数据和与这些数据相关的运算封装在一起的集合体 类的定义 34 类的定义格式 class类名 private 成员数据 成员函数 public 成员数据 成员函数 protected 成员数据 成员函数 关键字 类名 私有 公有 保护 classStudent private charName 20 floatMath floatChiese public floataverage voidSetName char name voidSetMath floatmath voidSetChinese floatch floatGetAverage void 分号不能少 35 用关键字priviate限定的成员称为私有成员 对私有成员限定在该类的内部使用 即只允许该类中的成员函数使用私有的成员数据 对于私有的成员函数 只能被该类内的成员函数调用 类就相当于私有成员的作用域 36 用关键字public限定的成员称为公有成员 公有成员的数据或函数不受类的限制 可以在类内或类外自由使用 对类而言是透明的 37 而用关键字protected所限定的成员称为保护成员 只允许在类内及该类的派生类中使用保护的数据或函数 即保护成员的作用域是该类及该类的派生类 38 39 每一个限制词 private等 在类体中可使用多次 一旦使用了限制词 该限制词一直有效 直到下一个限制词开始为止 如果未加说明 类中成员默认的访问权限是private 即私有的 40 classStudent charName 20 floatMath floatChiese public floataverage voidSetName char name voidSetMath floatmath voidSetChinese floatch floatGetAverage void 均为私有权限 均为公有权限 41 classA floatx y public voidSetxy floata floatb x a y b voidPrint void cout x t y endl A 私有数据 公有函数 在类外不能直接使用x或y 必须通过Setxy 给x或y赋值 通过Print 输出x或y 成员函数与成员数据的定义不分先后 可以先说明函数原型 再在类体外定义函数体 classA floatx y public voidSetxy floata floatb x a y b voidPrint void cout x t y endl 在类体内定义成员函数 43 classA floatx y public voidSetxy floata floatb voidPrint void voidA Setxy floata floatb x a y b voidA Print void cout x t y endl 在类体内说明成员函数原型 在类体外定义成员函数 44 函数体 在类体外定义成员函数的格式 voidA Setxy floata floatb x a y b 函数类型 类名 函数名 形参列表 函数体 45 在定义一个类时 要注意如下几点 1 类具有封装性 并且类只是定义了一种结构 样板 所以类中的任何成员数据均不能使用关键字extern auto或register限定其存储类型 2 在定义类时 只是定义了一种导出的数据类型 并不为类分配存储空间 所以 在定义类中的数据成员时 不能对其初始化 如 classTest intx 5 y 6 是不允许的externfloatx 是不允许的 46 在C 语言中 结构体类型只是类的一个特例 结构体类型与类的唯一的区别在于 在类中 其成员的缺省的存取权限是私有的 而在结构体类型中 其成员的缺省的存取权限是公有的 47 内联成员函数 当我们定义一个类时 可以在类中直接定义函数体 这时成员函数在编译时是作为内联函数来实现的 同时 我们也可以在类体外定义类的内联成员函数 在类体内说明函数 在类体外定义时 在成员函数的定义前面加上关键字inline classA floatx y public voidSetxy floata floatb voidPrint void inlinevoidA Setxy floata floatb x a y b inlinevoidA Print void cout x t y endl 说明该成员函数为内联 48 对象 只有在定义了属于类的变量后 系统才会为类的变量分配空间 在定义类时 只是定义了一种数据类型 即说明程序中可能会出现该类型的数据 并不为类分配存储空间 类的变量我们称之为对象 对象是类的实例 定义对象之前 一定要先说明该对象的类 49 不同对象占据内存中的不同区域 它们所保存的数据各不相同 但对成员数据进行操作的成员函数的程序代码均是一样的 存储类型 类名对象1 对象2 Studentst1 st2 对象的定义格式 类名 对象名 在建立对象时 只为对象分配用于保存数据成员的内存空间 而成员函数的代码为该类的每一个对象所共享 50 对象的定义方法同结构体定义变量的方法一样 也分三种 当类中有数据成员的访问权限为私有时 不允许对对象进行初始化 classA floatx y public voidSetxy floata floatb x a y b voidPrint void cout x t y endl a1 a2 voidmain void Aa3 a4 定义全局对象 定义局部对象 51 对象的使用 一个对象的成员就是该对象的类所定义的成员 有成员数据和成员函数 引用时同结构体变量类似 用 运算符 52 classA floatx y public floatm n voidSetxy floata floatb x a y b voidPrint cout x t y endl voidmain void Aa1 a2 定义对象a1 m 10 a1 n 20 为公有成员数据赋值a1 Setxy 2 0 5 0 为私有成员数据赋值a1 Print 10 20 2 0 5 0 输出 25 53 用成员选择运算符 只能访问对象的公有成员 而不能访问对象的私有成员或保护成员 若要访问对象的私有的数据成员 只能通过对象的公有成员函数来获取 54 classA floatx y public floatm n voidSetxy floata floatb x a y b voidPrint void cout x t y endl voidmain void Aa1 a2 a1 m 10 a1 n 20 为公有成员数据赋值 a1 x 2 a1 y 5 a1 Setxy 2 0 5 0 a1 Print 必须通过类内公有函数访问私有数据成员 非法 私有成员不能在类外访问 55 同类型的对象之间可以整体赋值 这种赋值与对象的成员的访问权限无关 classA floatx y public floatm n voidSetxy floata floatb x a y b voidPrint void cout x t y endl voidmain void Aa1 a2 a1 m 10 a1 n 20 为公有成员数据赋值a1 Setxy 2 0 5 0 a2 a1 a1 Print a2 Print 同类型的对象之间可以整体赋值 相当于成员数据间相互赋值 56 类体的区域称为类作用域 类的成员函数与成员数据 其作用域都是属于类的作用域 仅在该类的范围内有效 故不能在主函数中直接通过函数名和成员名来调用函数 类作用域 类类型的作用域和对象的作用域 57 classA floatx y public floatm n voidSetxy floata floatb x a y b voidPrint void cout x t y endl voidmain void Aa1 a2 a1 m 20 a1 n 10 a1 Setxy 2 0 5 0 a1 Print voidmain void Aa1 a2 m 20 n 10 Setxy 2 0 5 0 Print 用对象名调用 不能直接调用 58 类类型的作用域 在函数定义之外定义的类 其类名的作用域为文件作用域 而在函数体内定义的类 其类名的作用域为块作用域 对象的作用域与前面介绍的变量作用域完全相同 全局对象 局部对象 局部静态对象等 59 classA floatx y public floatm n voidSetxy floata floatb x a y b voidPrint void cout x t y endl a3 a4 voidmain void Aa1 a2 classB inti j public voidSetij intm intn i m j n Bb1 b2 a1 Setxy 2 0 5 0 b1 Setij 1 2 类A 文件作用域 在整个文件中有效 类B 块作用域 在函数内有效 全局对象 局部对象 60 类的嵌套 在定义一个类时 在其类体中又包含了一个类的完整定义 称为类的嵌套 类是允许嵌套定义的 61 classA classB inti j public voidSetij intm intn i m j n floatx y public Bb1 b2 voidSetxy floata floatb x a y b voidPrint void cout x t y endl 类B包含在类A中 为嵌套定义 嵌套类的对象 在类A的定义中 并不为b1 b2分配空间 只有在定义类A的对象时 才为嵌套类的对象分配空间 嵌套类的作用域在类A的定义结束时结束 62 类的对象如何引用私有数据成员 1 通过公有函数为私有成员赋值 classTest intx y public voidSetxy inta intb x a y b voidPrintxy void cout x x t y y endl voidmain void Testp1 p2 p1 Setxy 3 5 p1 Printxy 调用公有函数为私有对象赋值 63 2 利用指针访问私有数据成员 classTest intx y public voidSetxy inta intb x a y b voidGetxy int px int py px x py y 提取x y值voidPrintxy cout x x t y y endl voidmain void Testp1 p2 p1 Setxy 3 5 inta b p1 Getxy 3 5 b a a px b py 3 5 输出 35 64 3 利用函数访问私有数据成员 classTest intx y public voidSetxy inta intb x a y b intGetx void returnx 返回x值intGety void returny 返回y值voidPrintxy void cout x x t y y endl voidmain void Testp1 p2 p1 Setxy 3 5 inta b a p1 Getx b p1 Gety 将a x b ycout a t b endl 函数值就是私有成员变量的值 65 4 利用引用访问私有数据成员 classTest intx y public voidSetxy inta intb x a y b voidGetxy int 3 5 b a px py 3 5 输出 35 66 成员函数的重载 类中的成员函数与前面介绍的普通函数一样 成员函数可以带有缺省的参数 也可以重载成员函数 重载时 函数的形参必须在类型或数目上不同 67 classTest intx y intm n public voidSetxy inta intb x a y b voidSetxy inta intb intc intd x a y b m c n d voidPrintxy intx cout m m t n n endl voidPrintxy void cout x x t y y endl voidmain void Testp1 p2 p1 Setxy 3 5 p2 Setxy 10 20 30 40 参数不同p1 Printxy p2 Printxy p2 Printxy 2 参数 类型不同 输出 x 3y 5 x 10y 20 m 30n 40 68 可以有缺省参数的成员函数 若形参不完全缺省 则必须从形参的右边开始缺省 69 缺省参数的成员函数 classA floatx y public floatSum void returnx y voidSet floata floatb 10 0 x a y b voidPrint void cout x x t y y endl voidmain void Aa1 a2 a1 Set 2 0 4 0 cout a1 a1 Print cout a1 sum a1 Sum endl a2 Set 20 0 cout a2 a2 Print cout a2 sum a2 Sum endl 不缺省参数 a1 x 2 a1 y 4 缺省参数 a2 x 20 a2 y 10 70 定义类的指针及如何用指针来引用对象 classA floatx y public floatSum void returnx y voidSet floata floatb x a y b voidPrint void coutSet 2 0 3 0 通过指针引用对象的成员函数p Print coutSum endl a2 Set 10 0 20 0 a2 Print 2 0 3 0 p a1 71 定义类的数组及数组中元素的引用 voidmain void Stustu 3 定义类的数组Stu pstu 定义类的指针pstu stu 为指针赋值inti stu 0 SetStudent A 90 90 通过数组元素的引用赋值stu 1 SetStudent B 80 80 stu 2 SetStudent C 70 70 for i 0 iShow 指针变量指向数组元素pstu 指针变量加一 指向下一元素 stu pstu 72 返回引用类型的成员函数 可以返回私有数据成员的引用 classA floatx y public float 73 this指针 不同对象占据内存中的不同区域 它们所保存的数据各不相同 但对成员数据进行操作的成员函数的程序代码均是一样的 classA intx y public voidSetxy inta intb x a y b Aa1 a2 a1 x a1 y a2 x a2 y a1 Setxy a2 Setxy a1 Setxy 1 2 a2 Setxy 3 4 this x a this y b 系统自动将对象的指针带到成员函数中 74 当对一个对象调用成员函数时 编译程序先将对象的地址赋给this指针 然后调用成员函数 每次成员函数存取数据成员时 也隐含使用this指针 this指针具有如下形式的缺省说明 Stu constthis 类名 即this指针里的地址是一个常量 75 构造函数和析构函数是在类体中说明的两种特殊的成员函数 构造函数是在创建对象时 使用给定的值来将对象初始化 析构函数的功能正好相反 是在系统释放对象前 对对象做一些善后工作 76 构造函数是类的成员函数 系统约定构造函数名必须与类名相同 构造函数提供了初始化对象的一种简单的方法 构造函数可以带参数 可以重载 同时没有返回值 77 classA floatx y public A floata floatb x a y b 构造函数 初始化对象floatSum void returnx y voidSet floata floatb x a y b Print void cout x x t y y endl voidmain void Aa1 2 0 3 0 定义时调用构造函数初始化Aa2 1 0 2 0 a2 Set 10 0 20 0 利用成员函数重新为对象赋值a1 Print a2 Print 78 对构造函数 说明以下几点 1 构造函数的函数名必须与类名相同 构造函数的主要作用是完成初始化对象的数据成员以及其它的初始化工作 2 在定义构造函数时 不能指定函数返回值的类型 也不能指定为void类型 3 一个类可以定义若干个构造函数 当定义多个构造函数时 必须满足函数重载的原则 79 4 构造函数可以指定参数的缺省值 5 若定义的类要说明该类的对象时 构造函数必须是公有的成员函数 如果定义的类仅用于派生其它类时 则可将构造函数定义为保护的成员函数 由于构造函数属于类的成员函数 它对私有数据成员 保护的数据成员和公有的数据成员均能进行初始化 80 classA floatx y public A floata floatb 10 x a y b A x 0 y 0 voidPrint void cout x t y endl voidmain void Aa1 a2 20 0 a3 3 0 7 0 a1 Print a2 Print a3 Print 00201037 带缺省参数的构造函数 不带参数的构造函数 每一个对象必须要有相应的构造函数 81 每一个对象必须要有相应的构造函数 若没有显式定义构造函数 系统默认缺省的构造函数 classA floatx y public A voidPrint void cout x t y endl 隐含的缺省的构造函数 Aa1 a2 只允许这样定义对象 对象开辟了空间 但没有初始化 82 对局部对象 静态对象 全局对象的初始化对于局部对象 每次定义对象时 都要调用构造函数 对于静态对象 是在首次定义对象时 调用构造函数的 且由于对象一直存在 只调用一次构造函数 对于全局对象 是在main函数执行之前调用构造函数的 83 classA intx y public A inta x a cout 1 n A inta intb x a y b cout 2 n Aa1 3 voidf void Ab 2 3 voidmain void Aa2 4 5 f f 1 2 2 2 84 classA floatx y public A floata floatb x a y b cout 初始化自动局部对象 n A x 0 y 0 cout 初始化静态局部对象 n A floata x a y 0 cout 初始化全局对象 n voidPrint void cout x t y endl Aa0 100 0 定义全局对象voidf void cout 进入f 函数 n Aa2 1 2 staticAa3 初始化局部静态对象 voidmain void cout 进入main函数 n Aa1 3 0 7 0 定义局部自动对象f f 初始化全局对象 进入main函数 初始化自动局部对象 进入f 函数 初始化局部静态变量 进入f 函数 初始化自动局部对象 初始化自动局部对象 85 缺省的构造函数 在定义类时 若没有定义类的构造函数 则编译器自动产生一个缺省的构造函数 其格式为 className className 缺省的构造函数并不对所产生对象的数据成员赋初值 即新产生对象的数据成员的值是不确定的 86 classA floatx y public A 缺省的构造函数 编译器自动产生 可以不写floatSum void returnx y voidSet floata floatb x a y b voidPrint void cout x x t y y endl voidmain void Aa1 a2 产生对象时 自动调用缺省的构造函数 不赋值a1 Set 2 0 4 0 cout a1 a1 Print cout a1 sum a1 Sum endl a2 Print 打印随机值 87 关于缺省的构造函数 说明以下几点 1 在定义类时 只要显式定义了一个类的构造函数 则编译器就不产生缺省的构造函数 2 所有的对象在定义时 必须调用构造函数 不存在没有构造函数的对象 88 classA floatx y public A floata floatb x a y b voidPrint void cout x t y endl voidmain void Aa1 Aa2 3 0 30 0 显式定义了构造函数 不产生缺省的构造函数 error 定义时 没有构造函数可供调用 89 3 在类中 若定义了没有参数的构造函数 或各参数均有缺省值的构造函数也称为缺省的构造函数 缺省的构造函数只能有一个 4 产生对象时 系统必定要调用构造函数 所以任一对象的构造函数必须唯一 90 classA floatx y public A floata 10 floatb 20 x a y b A voidPrint void cout x t y endl voidmain void Aa1 Aa2 3 0 30 0 两个函数均为缺省的构造函数 两个构造函数均可供调用 构造函数不唯一 91 构造函数与new运算符 可以使用new运算符来动态地建立对象 建立时要自动调用构造函数 以便完成初始化对象的数据成员 最后返回这个动态对象的起始地址 用new运算符产生的动态对象 在不再使用这种对象时 必须用delete运算符来释放对象所占用的存储空间 用new建立类的对象时 可以使用参数初始化动态空间 92 classA floatx y public A floata floatb x a y b A x 0 y 0 voidPrint void coutPrint pa2 Print deletepa1 用delete释放空间deletepa2 用delete释放空间 500 93 析构函数 析构函数的作用与构造函数正好相反 是在对象的生命期结束时 释放系统为对象所分配的空间 即要撤消一个对象 析构函数也是类的成员函数 定义析构函数的格式为 ClassName ClassName 函数体 94 析构函数的特点如下 1 析构函数是成员函数 函数体可写在类体内 也可写在类体外 2 析构函数是一个特殊的成员函数 函数名必须与类名相同 并在其前面加上字符 以便和构造函数名相区别 3 析构函数不能带有任何参数 不能有返回值 不指定函数类型 95 在程序的执行过程中 当遇到某一对象的生存期结束时 系统自动调用析构函数 然后再收回为对象分配的存储空间 4 一个类中 只能定义一个析构函数 析构函数不允许重载 5 析构函数是在撤消对象时由系统自动调用的 96 classA floatx y public A floata floatb x a y b cout 调用非缺省的构造函数 n A x 0 y 0 cout 调用缺省的构造函数 n A cout 调用析构函数 n voidPrint void cout x t y endl voidmain void Aa1 Aa2 3 0 30 0 cout 退出主函数 n 调用缺省的构造函数 调用非缺省的构造函数 退出主函数 调用析构函数 调用析构函数 97 在程序的执行过程中 对象如果用new运算符开辟了空间 则在类中应该定义一个析构函数 并在析构函数中使用delete删除由new分配的内存空间 因为在撤消对象时 系统自动收回为对象所分配的存储空间 而不能自动收回由new分配的动态存储空间 98 用new运算符为对象分配动态存储空间时 调用了构造函数 用delete删除这个空间时 调用了析构函数 当使用运算符delete删除一个由new动态产生的对象时 它首先调用该对象的析构函数 然后再释放这个对象占用的内存空间 可以用new运算符为对象分配存储空间 如 A p p newA 这时必须用delete才能释放这一空间 deletep 99 classA floatx y public A floata floatb x a y b coutPrint deletepa1 调用析构函数cout 退出main 函数 n 进入main 函数 调用了构造函数 35 调用了析构函数 退出main 函数 100 不同存储类型的对象调用构造函数及析构函数 1 对于全局定义的对象 在函数外定义的对象 在程序开始执行时 调用构造函数 到程序结束时 调用析构函数 2 对于局部定义的对象 在函数内定义的对象 当程序执行到定义对象的地方时 调用构造函数 在退出对象的作用域时 调用析构函数 3 用static定义的局部对象 在首次到达对象的定义时调用构造函数 到程序结束时 调用析构函数 101 4 对于用new运算符动态生成的对象 在产生对象时调用构造函数 只有使用delete运算符来释放对象时 才调用析构函数 若不使用delete来撤消动态生成的对象 程序结束时 对象仍存在 并占用相应的存储空间 即系统不能自动地调用析构函数来撤消动态生成的对象 102 classA floatx y public A floata floatb x a y b cout 初始化自动局部对象 n A x 0 y 0 cout 初始化静态局部对象 n A floata x a y 0 cout 初始化全局对象 n A cout 调用析构函数 endl Aa0 100 0 定义全局对象voidf void cout 进入f 函数 n Aab 10 0 20 0 定义局部自动对象staticAa3 初始化局部静态对象 voidmain void cout 进入main函数 n f f 初始化全局对象 进入main函数 初始化自动局部对象 进入f 函数 初始化静态局部对象 进入f 函数 初始化自动局部对象 调用析构函数 调用析构函数 调用析构函数 调用析构函数 103 动态构造及析构对象数组 用new运算符来动态生成对象数组时 自动调用构造函数 而用delete运算符来释放p1所指向的对象数组占用的存储空间时 在指针变量的前面必须加上 才能将数组元素所占用的空间全部释放 否则 只释放第0个元素所占用的空间 pa1 newA 3 delete pa1 104 classA floatx y public A floata 0 floatb 0 x a y b cout 调用了构造函数 n voidPrint void cout x t y endl A cout 调用了析构函数 n voidmain void cout 进入main 函数 n A pa1 pa1 newA 3 开辟数组空间cout n完成开辟数组空间 n n delete pa1 必须用 删除开辟的空间cout 退出main 函数 n 进入main 函数 调用了构造函数 调用了构造函数 调用了构造函数 完成开辟数组空间 调用了析构函数 调用了析构函数 调用了析构函数 退出main 函数 105 缺省的析构函数 若在类的定义中没有显式地定义析构函数时 则编译器自动地产生一个缺省的析构函数 其格式为 ClassName ClassName 任何对象都必须有构造函数和析构函数 但在撤消对象时 要释放对象的数据成员用new运算符分配的动态空间时 必须显式地定义析构函数 106 实现类型转换的构造函数 同类型的对象可以相互赋值 相当于类中的数据成员相互赋值 如果直接将数据赋给对象 所赋入的数据需要强制类型转换 这种转换需要调用构造函数 107 classA floatx y public A floata floatb x a y b cout 调用构造函数 n A cout 调用析构函数 n voidPrint void cout x t y endl voidmain void Aa1 1 0 10 0 a1 Print a1 A 3 0 30 0 a1 Print cout 退出主函数 n 调用构造函数 产生临时对象 初始化并赋值后立即释放 110 调用构造函数 调用析构函数 330 退出主函数 调用析构函数 108 注意 当构造函数只有一个参数时 可以用 强制赋值 classB floatx public B floata x a cout 调用构造函数 n B cout 调用析构函数 n voidPrint void cout x endl voidmain void Bb1 1 0 b1 Print Bb2 100 b2 Print b1 10 b1 Print cout 退出主函数 n 调用构造函数 单参数可以这样赋值 1 调用构造函数 100 调用构造函数 调用析构函数 10 退出主函数 调用析构函数 调用析构函数 b1 B 10 产生一个临时对象 109 完成拷贝功能的构造函数 可以在定义一个对象的时候用另一个对象为其初始化 即构造函数的参数是另一个对象的引用 这种构造函数常为完成拷贝功能的构造函数 完成拷贝功能的构造函数的一般格式为 ClassName ClassName ClassName 函数体完成对应数据成员的赋值 110 classA floatx y public A floata 0 floatb 0 x a y b A A voidmain void Aa1 1 0 2 0 Aa2 a1 形参必须是同类型对象的引用 实参是同类型的对象 111 classA floatx y public A floata 0 floatb 0 x a y b cout 调用了构造函数 n A A 调用了构造函数调用了完成拷贝功能的构造函数1212调用了析构函数调用了析构函数 用已有的对象中的数据为新创建的对象赋值 112 如果没有定义完成拷贝功能的构造函数 编译器自动生成一个隐含的完成拷贝功能的构造函数 依次完成类中对应数据成员的拷贝 A A A 隐含的构造函数 113 classA floatx y public A floata 0 floatb 0 x a y b cout 调用了构造函数 n voidPrint void cout x t y endl A cout 调用了析构函数 n voidmain void Aa1 1 0 2 0 Aa2 a1 Aa3 a1 可以这样赋值a1 Print a2 Print a3 Print 调用了构造函数121212调用了析构函数调用了析构函数调用了析构函数 隐含了拷贝的构造函数 114 由编译器为每个类产生的这种隐含的完成拷贝功能的构造函数 依次完成类中对应数据成员的拷贝 但是 当类中的数据成员中使用new运算符 动态地申请存储空间进行赋初值时 必须在类中显式地定义一个完成拷贝功能的构造函数 以便正确实现数据成员的复制 115 构造函数与对象成员 对类A的对象初始化的同时还要对其成员数据类B的对象进行初始化 所以 类A的构造函数中要调用类B的构造函数 classB classA intx y Bb1 b2 在类A中包含类B的对象 116 classA floatx y public A inta intb x a y b voidShow cout x x t y y n classC floatz Aa1 类C的数据成员为类A的对象a1public C inta intb intc a1 b c z a 类C的对象初始化voidShow cout z a n a1 Show voidmain void Cc1 1 2 3 对类C的对象初始化c1 Show 在类C中调用类A的成员函数 利用类A的构造函数对类A的对象初始化 117 ClassName ClassName args c1 args1 cn agrsn 对其它成员的初始化 初始化对象成员的参数 实参 可以是表达式 也可以仅对部分对象成员进行初始化 118 classA floatx y public A inta intb x a y b voidShow cout x x t y y n classB floatx1 y1 public B inta intb x1 a y1 b voidShow cout x1 x1 t y y n classC floatz Aa1 Bb1 public C inta intb intc intd inte a1 a b c b1 a d z e voidShow cout z a n a1 Show b1 Show voidmain void Cc1 1 2 3 4 5 对类C的对象初始化 对象初始化的参数可以是表达式 119 对对象成员的构造函数的调用顺序取决于这些对象成员在类中说明的顺序 与它们在成员初始化列表中的顺序无关 当建立类ClassName的对象时 先调用各个对象成员的构造函数 初始化相应的对象成员 然后才执行类ClassName的构造函数 初始化类ClassName中的其它成员 析构函数的调用顺序与构造函数正好相反 120 classA floatx public A inta x a cout 调用了A的构造函数 n A cout 调用了A的析构函数 n classB floaty public B inta y a cout 调用了B的构造函数 n B cout 调用了B的析构函数 n classC floatz Bb1 Aa1 public C inta intb intc a1 a b1 b z c cout 调用了C的构造函数 n C cout 调用了C的析构函数 n voidmain void Cc1 1 2 3 调用了B的构造函数 调用了A的构造函数 调用了C的构造函数 调用了C的析构函数 调用了A的析构函数 调用了B的析构函数 121 在C 中所谓 继承 就是在一个已存在的类的基础上建立一个新的类 已存在的类称为 基类 baseclass 或 父类 fatherclass 新建立的类称为 派生类 derivedclass 或 子类 sonclass 122 类A派生类B 类A为基类 类B为派生类 A B 新增加的成员数据和成员函数 123 在C 语言中 一个派生类可以从一个基类派生 也可以从多个基类派生 从一个基类派生的继承称为单继承 从多个基类派生的继承称为多继承 124 通过继承机制 可以利用已有的数据类型来定义新的数据类型 所定义的新的数据类型不仅拥有新定义的成员 而且还同时拥有旧的成员 我们称已存在的用来派生新类的类为基类 又称为父类 由已存在的类派生出的新类称为派生类 又称为子类 125 在建立派生类的过程中 基类不会做任何改变 派生类则除了继承基类的所有可引用的成员变量和成员函数外 还可另外定义本身的成员变量和处理这些变量的函数 由于派生类可继承基类的成员变量和成员函数 因此在基类中定义好的数据和函数等的程序代码可重复使用 这样可以提高程序的可靠性 126 当从已有的类中派生出新的类时 可以对派生类做以下几种变化 1 可以继承基类的成员数据或成员函数 2 可以增加新的成员变量 3 可以增加新的成员函数 4 可以重新定义已有的成员函数 5 可以改变现有的成员属性 127 类A派生类B 类A为基类 类B为派生类 A B 但派生并不是简单的扩充 有可能改变基类的性质 有三种派生方式 公有派生 保护派生 私有派生 classB publicA classB protectedA classB privateA 默认的是私有派生 classB A A为私有派生 128 从一个基类派生一个类的一般格式为 classClassName BaseClassName private 私有成员说明public 公有成员说明protected 保护成员说明 派生类名 基类名 继承方式 public 表示公有基类private 表示私有基类 默认 protected 表示保护基类 派生类中新增加的成员 129 公有派生classClassName publicBaseClassName公有派生时 基类中所有成员在派生类中保持各个成员的访问权限 公有派生 派生类中保持基类的成员特性 基类 public 在派生类和类外可以使用protected 在派生类中使用private 不能在派生类中使用 130 A B public x在类B新增加的成员中不能直接调用 y在类B中可以调用 z在整个文件中可以调用 对类B的对象初始化即是对x y z m n等全部成员的初始化 131 classA intx protected inty public intz A inta intb intc x a y b z c 基类初始化intGetx returnx 返回xintGety returny 返回yvoidShowA cout x x t y y t z z n classB publicA intm n public B inta intb intc intd inte A a b c m d n e voidShow cout m m t n n n cout x Getx t y y t z z n intSum return Getx y z m n voidmain void Bb1 1 2 3 4 5 b1 ShowA b1 Show cout Sum b1 Sum n cout x b1 Getx t cout y b1 Gety t cout z b1 z n 公有派生 对基类初始化 因为x是基类私有 所以在派生类和类外中不能直接引用 因为y是基类保护 所以在派生类中可以直接引用 而在类外不可直接引用 因为z是基类公有 所以在派生类中和类外均可直接引用 132 私有派生classClassName privateBaseClassName私有派生时 基类中公有成员和保护成员在派生类中均变为私有的 在派生类中仍可直接使用这些成员 基类中的私有成员 在派生类中不可直接使用 私有派生 派生类中基类公有和保护成员成为私有 基类 public 变为私有 在派生类中使用 类外不可使用protected 变为私有 在派生类中使用 类外不可使用private 不能在派生类中和类外使用 133 A B private x在类B新增加的成员中不能直接调用 y在类B中可以调用 z在类B中可以调用 对类B的对象初始化即是对x y z m n等全部成员的初始化 均为私有类B外不能引用 134 classA intx protected inty public intz A inta intb intc x a y b z c 基类初始化intGetx returnx 返回xintGety returny 返回yvoidShowA cout x x t y y t z z n classB privateA intm n public B- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序设计 谭浩强 完整版
装配图网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文