标准C++技术培训.ppt_第1页
标准C++技术培训.ppt_第2页
标准C++技术培训.ppt_第3页
标准C++技术培训.ppt_第4页
标准C++技术培训.ppt_第5页
已阅读5页,还剩516页未读 继续免费阅读

下载本文档

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

文档简介

C 编程技术基础培训 北京神州数码思特奇信息技术股份有限公司研究院 1 课程目标 本课程帮助学员对C 语言编程技术的基本语法概念 内存管理 模板库 线程编程 数据库访问技术等方面进行培训与指导 并结合实际应用项目达到认识和掌握各种编程知识的目的 让学员掌握C 技术编程思想 方法和解决实际问题的技巧 本课程把概念 知识点与案例相结合 进行案例教学 课程目标 2 课程安排 第一部分 C 语言概述第二部分 类与对象第三部分 继承与派生第四部分 运算符重载与命名空间第五部分 IO流类库第六部分 C 的内存格局第七部分 STL标准模板库第八部分 C 多线程编程与网络通讯基础第九部分 数据库访问技术 项目片段分析 3 一 C 语言概述 C 语言优势程序的版式命名规则表达式和基本语句编写规则函数编写规则程序结构编译环境介绍 4 C 语言的优势 总的来说 C 语言具有4个方面的优点 1 降低程序开发和维护的成本 2 比用C语言编写的程序更加有效率 3 C 允许程序员更自由地使用各种库 4 C 的异常处理机制能够保证在运行期间检查到错误 并转至相应的处理程序 减少了代码的长度和复杂度 5 程序的版式 1 文件结构版权和版本头文件的作用头文件和定义文件的结构 正确使用include ifndef define endif目录结构2 版式空行 代码行代码行内的空格对齐修饰符 的位置注释类的版式 public private前后之争 6 命名规则 不要最求世界上最好的命名规则 在机构内部一致即可 匈牙利法的利弊 一些共性规则 直观并且可以拼读 可望文知意 不必 解码 名字的长度 min length max information原则与操作系统和开发工具的风格保持一致程序中不要出现仅靠大小写区分的相似的标识符程序中不要出现标识符完全相同的局部变量和全局变量变量的名字应当使用 名词 或者 形容词 名词 全局函数的名字应当使用 动词 或者 动词 名词 动宾词组 类的成员函数应当只使用 动词 被省略掉的名词就是对象本身 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等尽量避免名字中出现数字编号 如Value1 Value2等 除非逻辑上的确需要编号 7 表达式和基本语句 1表达式如果代码行中的运算符比较多 用括号确定表达式的操作顺序 避免使用默认的优先级 不要编写太复杂的复合表达式 不要把程序中的复合表达式与 真正的数学表达式 混淆 例如if a b c 2你会编写正确的if语句吗布尔变量与零值比较整型变量与零值比较浮点变量与零值比较指针变量与零值比较为什么有人用If NULL P 这样 古怪 的格式3循环语句在多重循环中 如果有可能 应当将最长的循环放在最内层 最短的循环放在最外层 以减少CPU跨切循环层的次数 如果循环体内存在逻辑判断 并且循环次数很大 宜将逻辑判断移到循环体的外面 建议for语句的循环控制变量的取值采用 半开半闭区间 写法 4switch goto 8 函数设计 1参数的规则参数的书写要完整 不要贪图省事只写参数的类型而省略参数名字 参数命名要恰当 顺序要合理 示例StringCopy char str1 char str2 如果参数是指针 且仅做输入用 则应在类型前加const 以防止该指针在函数体内被意外修改 避免函数有太多的参数 参数个数尽量控制在5个以内 如果参数太多 在使用时容易将参数类型或顺序搞错 尽量不要使用类型和数目不确定的参数 例如printf2返回值的规则不要省略返回值的类型 函数名字与返回值类型在语义上不可冲突 例如getchar不要将正常值和错误标志混在一起返回 正常值用输出参数获得 而错误标志用return语句返回 有时候函数原本不需要返回值 但为了增加灵活性如支持链式表达 可以附加返回值 例如char strcpy char strDest constchar strSrc 3函数内部实现的规则 在函数体的 入口处 和 出口处 从严把关在函数体的 入口处 对参数的有效性进行检查 在函数体的 出口处 对return语句的正确性和效率进行检查 9 4一些建议函数的功能要单一 不要设计多用途的函数 函数体的规模要小 尽量控制在50行代码之内 尽量避免函数带有 记忆 功能 相同的输入应当产生相同的输出 带有 记忆 功能的函数 其行为可能是不可预测的 因为它的行为可能取决于某种 记忆状态 不仅要检查输入参数的有效性 还要检查通过其他途径进入函数体内的变量的有效性 例如全局变量 文件句柄等 用于出错处理的返回值一定要清楚 让使用者不容易忽视或误解错误情况 5使用断言使用断言捕捉不应该发生的非法情况 不要混淆非法情况与错误情况之间的区别 后者是必然存在的并且是一定要做出处理的 在函数的入口处 使用断言检查参数的有效性 合法性 在编写函数时 要进行反复的考查 并且自问 我打算做哪些假定 一旦确定了的假定 就要使用断言对假定进行检查 函数设计 10 C 程序结构 从总体上看 C 程序文件一般可以分成4个部分 预处理指令 全局说明 程序的主函数和用户自定义函数 预处理指令就是源程序中所包含的各种编译指令 所有的预处理指令都以 开始 全局说明一般包括一些程序所要使用的全局变量 类说明等等任何一个C 程序都有且仅有一个主函数main 文件格式 hC的头包含文件 cppC 的源程序 hppC 的头包含文件 11 C 语言常用编译器 Linux平台下的GNU编译器Quincy99集成开发编译器MSVisualC 编译器BolandC Builder编译器Eclipse集成编译器 12 VC中编程开发 13 VC中编程开发 14 课程安排 第一部分 C 语言概述第二部分 类与对象第三部分 继承与派生第四部分 运算符重载与命名空间第五部分 IO流类库第六部分 C 的内存格局第七部分 STL标准模板库第八部分 C 多线程编程与网络通讯基础第九部分 数据库访问技术 项目片段分析 15 类的封装 多态 1面向对象的基本概念 4指针应用 6对象数组与对象指针 10模板 11程序实训 二 类与对象 3构造函数 拷贝构造函数 深拷贝 浅拷贝 析构函数 5创建对象 7友元 8对象成员常类型 常对象 常指针 9常类型 常对象 常指针 16 许多对象具有相同的结构和特性 例如不管是数学书还是化学书 它们都具有大小 定价 编者等特性 在现实生活中 我们通常将具有相同性质的事物归纳 划分成一类 例如数学书和化学书都属于书这一类 同样在面向对象程序设计中也会采用这种方法 面向对象方法中的类是具有相同属性和行为的一组对象的集合 类代表了一组对象的共性和特征 类是对象的抽象 而对象是类的具体实例 例如 家具设计师按照家具的设计图做成一把椅子 那么设计图就好比是一个类 而做出来的椅子则是该类的一个对象 一个具体实例 类 1面向对象的基本概念 17 类的封装 类的封装就是将对象的属性和行为结合成一个独立的实体 并尽可能隐蔽对象的内部细节 对外形成一道屏障 只保留有限的对外接口使之和外界发生联系 类的成员包括数据成员和成员函数 分别描述类所表达问题的属性和行为 对类成员的访问加以控制就形成了类的封装 这种控制是通过设置成员的访问权限来实现的 在面向对象程序设计中 通过封装将一部分行为作为外部接口 而将数据和其它行为进行有效的隐蔽 就可以达到对数据访问权限的合理控制 把整个程序中不同部分的相互影响减少到最低限度 2类的封装 多态 18 类的概念和定义 classWatch public voidSetTime intNewH intNewM intNewS voidShowTime private intHour Minute Second 成员数据 成员函数 类的定义 19 关键字class说明了类定义的开始 类中所有的内容用大括号括起来 类的成员可分为三种级别的访问权限 public 公有的 说明该成员是公有的 它不但可以被类的成员函数访问 而且可以被外界访问 所以说公有类型定义了类的外部接口 Protected 保护的 说明该成员只能被该类的成员函数和该类的派生类的成员函数访问 Private 私有的 说明该成员只能被类的成员函数访问 外界不能直接访问它 类的数据成员一般都应该声明为私有成员 2类的封装 多态 20 类的多态 2类的封装 多态 多态性是指在一般类中定义的属性或行为 被特殊类继承之后 可以具有不同的数据类型或表现出不同的行为 这使得同一个属性或行为在一般类及其各个特殊类中具有不同的语义 例如 数的加法 实数的加法 复数的加法 21 在建立一个对象时 常常需要作一些初始化工作 而当对象使用结束时 又需要作一些清理工作 在C 中提供了两个特殊的成员函数来完成这两项工作 那就是构造函数和析构函数 构造函数的作用就是在对象在被创建时利用特定的值构造对象 将对象初始化 构造函数和析构函数 3类的构造函数 拷贝构造函数与析构函数 22 默认拷贝构造函数在类定义中如果没有提供自己的拷贝构造函数 则C 提供一个默认的构造函数 其拷贝策略是逐个成员依次拷贝 深拷贝和浅拷贝默认拷贝构造函数均是浅拷贝但是一个类可能拥有其它资源 如其构造函数分配了一个堆内存 析构函数释放了这个内存 则此时就需要进行深拷贝了深拷贝不能依赖编译器实现 3类的构造函数 拷贝构造函数与析构函数 23 如何把数据赋给对象的数据成员 有三种方法 其一 当类定义时把数据成员定义成公有成员时 可用传统的方法给它赋初值 C语言传统的方法 voidmain structstudent intsno char sname floatscore structstudents1 9801 张三 89 5 其二 用成员函数赋初值classInit inti char name public setdata intn char namep i n name namep voidmain InitC C setdata 34 program 3类的构造函数 拷贝构造函数与析构函数 24 其三 对于更一般的类型 我们用构造函数的方法 构造函数是特殊成员函数 具有一些特殊的性质 1 构造函数的名字必须与类名相同 2 构造函数可以有任意类型的参数 但不能具有返回类型 3 定义对象时 编译系统会自动地调用构造函数 4 构造函数也是成员函数 函数体可写在类体内 也可写在类体外 5 构造函数被声明为公有函数 但它不能象其他成员函数那样被显式地调用 它是在定义对象的同时被调用的 3类的构造函数 拷贝构造函数与析构函数 25 classcomplex private doublereal imag public complex doubler doublei real r imag i doubleabscomplex doublet t real real imag imag returnsqrt t 构造函数不能像其它成员函数那样被显式地调用 它是在定义对象的同时调用的 通常 创建对象有以下两种方法 1 利用构造函数直接创建对象 其一般格式为 类名对象名 实参表 3类的构造函数 拷贝构造函数与析构函数 26 例 include includeclasscomplex private doublereal imag public complex doubler doublei 构造函数 real r imag i doubleabscomplex doublet t real real imag imag returnsqrt t voidmain complexA 1 1 2 2 定义对象A时自动调用构造函数complexcout 复数A的绝对值 A abscomplex endl 3类的构造函数 拷贝构造函数与析构函数 27 2 利用构造函数创建对象时 通过对象指针 用new申请一个空间作为对象其一般格式为 类名 对象指针 new类名 如 complex A newcomplex 1 1 2 2 voidmain complex A newcomplex 1 1 2 2 定义对象指针A时 用new申请一个空间作为对象 A指向该空间 并自动调用构造函数complexcout 复数A的绝对值 A abscomplex endl 说明 1 通常需要给每个类定义构造函数 如果没有给类定义构造函数 则编译系统自动地生成一个缺省的构造函数 complex complex 不能带任何参数 2 构造函数可采用构造初始化表对数据成员进行初始化 这是某些程序员喜欢使用的方法 classA inti j floatf public A intI intJ floatF i I j J f F 28 示例1 includeclassmyclass public charname 10 intno voidmain myclassa chen 25 cout a name a no endl 3类的构造函数 拷贝构造函数与析构函数 29 示例2 include includeclassmyclass public charname 10 intno public myclass char a intn no n strcpy name a voidmain char c chen myclassa c 25 cout a name a no endl 3类的构造函数 拷贝构造函数与析构函数 30 示例3 include includeclassmyclass public charname 10 intno char str public myclass char a intn no n strcpy name a myclass char a str newchar strlen a 1 strcpy str a myclass deletestr cout 析构函数调用 endl voidmain char c chen myclassa c 25 cout a name a no endl myclassb c cout b str endl 3类的构造函数 拷贝构造函数与析构函数 31 默认参数的构造函数 如果希望在定义对象时会自动给一个默认值 这时可以定义一个带默认参数的构造函数 classcomplex private doublereal imag public complex doubler 0 0 doublei 0 0 带默认参数的构造函数doubleabscomplex 成员函数 complex complex doubler 0 0 doublei 0 0 real r imag i 带默认参数的构造函数完整定义doublecomplex abscomplex 成员函数完整定义 doublet t real real imag imag returnsqrt t complexS1 S1为0 0 0 0的对象complexS2 1 1 只给一个参数complexS3 1 1 2 2 给二个参数 32 析构函数 析构函数也是特殊成员函数 用于释放对象 当撤消对象时 编译系统会自动地调用析构函数 例 include includeclasscomplex private doublereal imag public complex doubler 0 0 doublei 0 0 带默认参数的构造函数 complex 声明析构函数doubleabscomplex 33 complex complex doubler doublei 带默认的构造函数 cout 进入构造函数 endl real r imag i complex complex 定义析构函数 为说明问题而定义 cout 进入析构函数 endl doublecomplex abscomplex doublet t real real imag imag returnsqrt t voidmain complexA 1 1 2 2 定义对象A时自动调用构造函数complexcout 复数A的绝对值 A abscomplex endl 结束时会自动调用析构函数 运行结果 进入构造函数 复数A的绝对值 2 459675进入析构函数 34 说明每个类必定有一个析构函数 如果没有给类定义析构函数 则编译系统自动地生成一个默认的析构函数 complex complex 对于大多数类 默认的析构函数就能满足要求 但是 如果在一个对象完成其使命之前要做一些内部处理 则应明确地定义析构函数 如 classstring data char str public string data char s str newchar strlen s 1 strcpy str s string data deletestr 35 当撤消对象时 编译系统会自动地调用析构函数外 在以下情况 析构函数也会被调用 如果一个对象被定义在一个函数体内 则当这个函数运行结束时 自动撤消所有的局部变量时也自动撤消该对象 该对象的析构函数被自动调用 如果一个对象是由new动态创建的 在用delete释放它时 该对象的析构函数也被自动调用 若程序不用delete释放对象时 系统是不会自动调用析构函数的 说明 36 程序例 分析下面程序中构造函数与析构函数的调用顺序 初始化列表的方法还可用于const成员和引用性成员 classexample private constintnum int 练习 37 重载构造函数 C 允许重载构造函数 这些构造函数之间以它们所带参数的个类或类型的不同而区分 同时具有没有参数的构造函数和带默认参数的构造函数时 这样的重载有可能产生二义性 classcomplex public complex complex doubler 0 0 complex complex cout 进入构造函数 endl complex complex doubler cout 进入构造函数 endl voidmain complexa 存在二义性 不知调用那一个构造函数complexb 1 1 正确 调用x inti 0 38 拷贝构造函数 拷贝构造函数是一种特殊的构造函数 它用于依据已存在的对象建立一个新对象 相当于对象赋值 拷贝构造函数的特点 1 因为该函数也是一种构造函数 所以其函数名与类名相同 并且该函数也没有返回值类型 2 该函数只有一个参数 并且是同类对象的引用 3 每个类都必须有一个拷贝构造函数 可由程序员自己定义 或由系统自动生成一个 默认的拷贝构造函数 1 自定义拷贝构造函数 形式如下 classname constclassname ob 拷贝构造函数函数体 39 例 includeclasspoint intx y public point inta intb x a y b 构造函数point constpoint 本例以 代入 法调用拷贝构造函数外 还可以采用 赋值 法调用拷贝构造函数 pointp2 p1 40 默认的拷贝构造函数 如果没有编写自定义的拷贝构造函数 C 会自动地将一个已存在的对象复制给新对象 这种按成员逐一复制的过程是由缺省拷贝构造函数自动完成的 例 includeclasspoint intx y public point inta intb x a y b 构造函数voidprint cout x y endl voidmain pointp1 30 40 定义类point的对象p1 调用了普通的构造函数pointp2 p1 以 代入 法调用默认拷贝构造函数 用对象p1初始化对象p2pointp3 p1 以 赋值 法调用默认拷贝构造函数 用对象p1初始化对象p3p1 print p2 print p3 print 说明 1 与一般的构造函数一样 拷贝构造函数没有返回值 2 通常默认的拷贝构造函数是能够胜任工作的 但若类中有指针类型时 按成员复制的方法会产生错误 41 浅拷贝与深拷贝 浅拷贝实现对象间数据元素的一一对应复制 深拷贝当被复制的对象数据成员是指针类型时 不是复制该指针成员本身 而是将指针所指的对象进行复制 42 浅拷贝与深拷贝 浅拷贝 通过一个例子来理解浅拷贝的概念 C语言的例子char p1 p2 p1 malloc 20 strcpy p1 BinWang p2 p1 BinWang 指针p1 指针p2 43 浅拷贝与深拷贝 浅拷贝 通过一个例子来理解浅拷贝的概念 C 的例子ClassString String String constchar String private char str String String str 0 String String if str 0 deletestr String String constchar s str newchar strlen s 1 strcpy str s String s1 newString BinWang String s2 newString s1 调用缺省拷贝构造函数 44 浅拷贝与深拷贝 浅拷贝 通过一个例子来理解浅拷贝的概念浅拷贝的缺点当一个指针指向同一个对象或内存单元时存在潜在的错误源泉 例如当对象s1被析构以后 对象s2无法析构是由于缺省拷贝构造函数引起的 必须重写 str str BinWang s1 s2 45 浅拷贝与深拷贝 深拷贝 ClassString String String constchar String String String String str 0 String String if str 0 deletestr String String constchar s str newchar strlen s 1 strcpy str s String String String 46 浅拷贝与深拷贝 深拷贝深拷贝可以很好地避免指针悬挂问题 str str BinWang s1 s2 BinWang 47 运行结果如下 Pleaseenterthenumberofpoints 2DefaultConstructorcalled DefaultConstructorcalled CopyofpointsArray1 Point 0ofarray2 5 10Point 1ofarray2 15 20AfterthemovingofpointsArray1 Point 0ofarray2 25 30Point 1ofarray2 35 40Deleting Destructorcalled Destructorcalled Deleting 接下来程序出现异常 也就是运行错误 48 例对象的浅拷贝 48 拷贝前 拷贝后 分析 49 50 例对象的深拷贝 程序的运行结果如下 Pleaseenterthenumberofpoints 2DefaultConstructorcalled DefaultConstructorcalled DefaultConstructorcalled DefaultConstructorcalled CopyofpointsArray1 Point 0ofarray2 5 10Point 1ofarray2 15 20AfterthemovingofpointsArray1 Point 0ofarray2 5 10Point 1ofarray2 15 20Deleting Destructorcalled Destructorcalled Deleting Destructorcalled Destructorcalled 50 拷贝前 拷贝后 分析 51 语法形式存储类型数据类型 指针名 初始地址 例 int pa 注意事项用变量地址作为初值时 该变量必须在指针初始化之前已说明过 且变量类型应与指针类型一致 可以用一个已赋初值的指针去初始化另一个指针变量 不要用一个内部auto变量去初始化static指针 4指针应用 52 例指针的声明 赋值与使用 includeusingnamespacestd intmain int i pointer 声明int型指针i pointerinti 声明int型数ii pointer 输出int型指针所指地址的内容 程序运行的结果是 Outputinti 10Outputintpointeri 10 53 例void类型指针的使用 voidvobject 错 不能声明void类型的变量void pv 对 可以声明void类型的指针int pint inti intmain pv 54 指向常量的指针 charch 5 lisi constchar pStr ch 表示指向的对象是常量 l i s i 0 pStr 0088 4400 0088 4400 指向内容不可改变 pStr w errorpStr wangwu ok ch 指针值可以修改 55 指针常量 charch 5 lisi char constpStr ch 表示指针本身是常量 l i s i 0 pStr 0088 4400 0088 4400 指针值不可修改 pStr zhangsan error pStr W ok ch 指向的内容可以修改 56 指针变量的算术运算 指针与整数的加减运算指针p加上或减去n 其意义是指针当前指向位置的前方或后方第n个数据的地址 这种运算的结果值取决于指针指向的数据类型 指针加一 减一运算指向下一个或前一个数据 例如 y px 相当于y px 和 优先级相同 自右向左运算 57 pa 指针变量的算术运算 58 指向数组元素的指针 声明与赋值例 inta 10 pa pa 通过指针引用数组元素经过上述声明及赋值后 pa就是a 0 pa 1 就是a 1 pa i 就是a i a i pa i a i pa i 都是等效的 不能写a 因为a是数组首地址是常量 59 指针数组 数组的元素是指针型例 Point pa 2 由pa 0 pa 1 两个指针组成 60 例利用指针数组存放单位矩阵 includeusingnamespacestd intmain intline1 1 0 0 声明数组 矩阵的第一行intline2 0 1 0 声明数组 矩阵的第二行intline3 0 0 1 声明数组 矩阵的第三行int p line 3 声明整型指针数组p line 0 line1 初始化指针数组元素p line 1 line2 p line 2 line3 输出单位矩阵cout Matrixtest endl for inti 0 i 3 i 对指针数组元素循环 for intj 0 j 3 j 对矩阵每一行循环 cout p line i j cout endl 输出结果为 Matrixtest 1 0 00 1 00 0 1 61 例二维数组举例 includeusingnamespacestd intmain intarray2 2 3 11 12 13 21 22 23 for inti 0 i 2 i cout array2 i endl for intj 0 j 3 j cout array2 i j 或者cout array2 i j cout endl 在某次运行之后 程序的输出结果为 0X0065FDE011 12 130X0065FDEC21 22 23 62 指向常量的指针做形参 includeusingnamespacestd constintN 6 voidprint constint p intn intmain intarray N for inti 0 i array i print array N voidprint constint p intn cout p for inti 1 i n i cout p i cout endl 63 声明形式存储类型数据类型 函数指针名 含义 数据指针指向数据存储区 而函数指针指向的是程序代码存储区 指向函数的指针 64 例函数指针 includeusingnamespacestd voidprint stuff floatdata to ignore voidprint message floatlist this data voidprint float floatdata to print void function pointer float intmain floatpi float 3 14159 floattwo pi float 2 0 pi print stuff pi function pointer print stuff function pointer pi function pointer print message function pointer two pi function pointer 13 0 function pointer print float function pointer pi print float pi voidprint stuff floatdata to ignore cout Thisistheprintstufffunction n voidprint message floatlist this data cout Thedatatobelistedis list this data endl voidprint float floatdata to print cout Thedatatobeprintedis data to print endl 运行结果 Thisistheprintstufffunction Thisistheprintstufffunction Thedatatobelistedis6 283180Thedatatobelistedis13 000000Thedatatobeprintedis3 141590Thedatatobeprintedis3 141590 65 指向类的非静态成员的指针 通过指向成员的指针只能访问公有成员声明指向成员的指针声明指向公有数据成员的指针类型说明符类名 指针名 声明指向公有函数成员的指针类型说明符 类名 指针名 参数表 66 指向类的非静态成员的指针 指向数据成员的指针说明指针应该指向哪个成员指针名 类名 数据成员名 通过对象名 或对象指针 与成员指针结合来访问数据成员对象名 类成员指针名或 对象指针名 类成员指针名 67 指向类的非静态成员的指针 指向函数成员的指针初始化指针名 类名 函数成员名 通过对象名 或对象指针 与成员指针结合来访问函数成员 对象名 类成员指针名 参数表 或 对象指针名 类成员指针名 参数表 68 指向类的非静态成员的指针 例访问对象的公有成员函数的不同方式intmain 主函数 PointA 4 5 声明对象APoint p1 69 指向类的静态成员的指针 对类的静态成员的访问不依赖于对象可以用普通的指针来指向和访问静态成员例通过指针访问类的静态数据成员例通过指针访问类的静态函数成员 70 5创建对象 通过使用数组 我们可以对大量的数据和对象进行有效的管理 但对于许多程序 在运行之前 我们并不能确切地知道数组中会有多少个元素 例如 一个网络中有多少个可用节点 一个CAD系统中会用到多少个形状等 如果数组开的太大会造成很大的浪费 如果数组较小则又影响大量数据的处理 在C 中 动态内存分配技术可以保证我们在程序运行过程中按实际需要申请适量的内存 使用结束后再进行释放 这种在程序运行过程中申请和释放存储单元的过程称为创建对象和删除对象 1 new运算符 71 C 用new运算符来创建对象 运算符new的功能是动态创建对象 其语法形式为 new类型名 初值列表 该语句的功能是在程序运行过程中申请用于存放指定类型的内存空间 并用初值列表中给出的值进行初始化 如果创建的对象是普通变量 初始化工作就是赋值 如果创建的对象是某一个类的实例对象 则要根据实际情况调用该类的构造函数 例如 int p p newint 100 赋值给指针变量例如 rectangle r r newrectangle 5 6 调用矩形类的构造函数如果创建的对象是数组类型 则应按照数组的结构来创建 语法形式为 5创建对象 72 一维数组 new类型名 下标 当数组为一维数组时 下标为数组为元素的个数 动态分配内存时不能指定数组元素的初值 如果内存申请成功 返回一个指向新分配内存的首地址的指定类型的指针 如果失败返回0 例如 int p p newint 10 多维数组 new类型名 下标1 下标2 当数组为多维数组时 返回一个指向新分配内存的首地址的指针 但该指针的类型为指定类型的数组 数组元素的个数为除最左边一维外下标的乘积 例如 int p 5 p newint 10 5 5创建对象 73 2 delete运算符 运算符delete的功能是删除由new运算符创建的对象 释放指针指向的内存空间 其语法形式为 delete指针名 例如 int p p newint 100 deletep 如果new运算符创建的对象是数组 则删除对象时应使用的语法形式为 delete 指针名 例如 int p p newint 10 delete p 5创建对象 74 3 C 程序实例 例 类对象的创建与删除 includeclassrectangle 定义一个矩形类 public rectangle floatlen floatwid 构造函数 length len width wid floatGetArea 成员函数private floatlength floatwidth 5创建对象 75 floatrectangle GetArea 成员函数实现returnlength width voidmain rectangle r 定义指向rectangle类的指针变量rr newrectangle 10 5 创建rectangle类对象coutGetArea endl deleter 删除对象 4 C 程序实例分析 程序中先建立了一个rectangle类 然后在主函数中定义了一个指向rectangle类的指针变量r 用new在内存中开辟一段空间以存放rectangle类对象 这时会自动调用构造函数来初始化该对象 接下来使用指向rectangle类的指针变量r得到矩形的面积 最后用delete删除对象 释放该空间 5创建对象 76 6对象数组与对象指针 对象数组当一个类有许多对象时 可以用类定义对象数组 例 includeclassexam intx public voidset x intn x n intget x returnx voidmain examob 4 inti for i 0 i 4 i ob i set x i for i 0 i 4 i cout ob i get x cout endl 77 以上的例中 没有明显的定义构造函数 因此对象数组四个元素的初值都由默认构造函数来建立 是不确定值 所以可用成员函数set x来设置 设计类时就要先考虑到定义对象数组时数组元素初始化的需要 当各个元素的初值要求相同时 可以在类内先设计不带参数的构造函数或带默认值的构造函数 当各个元素的初值要求不同时 可以在类内先设计带参数 无默认值 的构造函数 在定义对象数组时 可用用初值表进行赋值 例 运行结果 1122334455661231231122334455667788 对象数组 78 定义二维数组对象时 如何对二维数组对象初始化 例 对象数组 79 对象指针 当需要时 可以用类定义对象指针 对象指针就是用于存放对象地址的变量1 用指针引用单个对象成员 用 操作符例 includeclassexample intx public voidset a inta x a voidshow a coutshow a 用对象指针访问对象成员函数 该函数又访问x 80 2 用对象指针引用对象数组voidmain exeob 2 p 定义exe类的对象数组ob和对象指针pob 0 set a 10 数组元素赋值ob 1 set a 20 p ob 数组名ob代表数组首元素地址 赋给p 即p指向ob 0 p show a p 移动指针 p指向ob 1 p shoe a 对象指针 81 this指针 当一个成员函数被调用时 C 自动产生一个参数 这个参数是一个类指针 叫this 可以指向该类的一个对象 这个对象就是接受该函数调用的对象 例 includeclassA intx public A intx1 x x1 voiddisp coutx voidmain Aa 1 b 2 cout a a disp this指向acout b b disp this指向b 82 示例 this指针 83 向函数传递对象 1 使用对象作为函数的参数在函数中用对象作为形参 在调用该函数时 也要用对象作为实参 而这时是把实参对象的值转给形参对象 即 值调用 includeclasstr inti public tr intn i n voidset i intn i n intget i returni voidsqr it trob 一个函数 形参是tr类的对象ob ob set i ob get i ob get i 形参对象值为 i i icout 形参对象i的值为 ob get i endl voidmain trobj 10 定义对象obj作为实参sqr it obj obj为实参调用函数sqr it trob cout 但是实参obj的i还是 cout obj get i endl 运行结果 形参对象i的值为100但是实参obj的i还是10 84 2 使用对象指针作为函数的参数在函数中用对象指针作为形参 在调用该函数时 要用对象地址 或也用对象指针作为实参 而这时是把实参对象的地址转给形参对象指针 即实参和形参同一地址空间 所谓 地址调用 例 includeclasstr inti public tr intn i n voidset i intn i n intget i returni voidsqr it tr ob ob set i ob get i ob get i couti的值为 get i endl voidmain trobj 10 定义对象obj作为实参sqr it 运行结果 形参对象指针ob i的值为100实参obj的i变成100 85 3 使用对象引用作为函数的参数在函数中用对象引用作为形参 在调用该函数时 用对象名作为实参 而这时是把实参对象名与形参对象名成为引用 相当于取别名 即实参和形参同一地址空间即 地址调用 例 includeclasstr inti public tr intn i n voidset i intn i n intget i returni voidsqr it tr voidmain trobj 10 定义对象obj作为实参sqr it obj obj为实参调用函数sqr it tr 运行结果 形参ob对象i的值为100实参obj的i变成100 86 7友元 2 友元函数 1 友元概述 3 友元类 87 在程序设计过程中 假如用户建立了一个类 这个类的数据成员被定义为私有 这时如果想把该数据存取到某个函数 非该类的成员函数 中 那么这样做肯定是不被允许的 但是有时候一些非成员函数需要亲自访问类中的某些私有数据 那么这时候就需要用到友元 友元提供了不同类或对象的成员函数之间 类的成员函数与一般函数之间进行数据共享的机制 通过友元 一个普通函数或类的成员函数可以访问到封装于其它类中的数据 友元的作用在于提高程序的运行效率 但同时它也破坏了类的封装性和隐藏性 使得非成员函数可以访问类的私有成员 1 友元概述 7友元 88 类的封装性 使类只能通过成员函数来访问私有成员 这是好事但也有一定的限制太死的感觉 能否开个小孔口 必要时作个破例 使外界函数 别的类的个别成员函数 甚致别的类的所有成员函数可访问某个类的私有成员 这个方法称为友元 有 友元函数 友元类二种 1 友元概述 7友元 89 友元函数是在类定义中由关键字friend修饰的非成员函数 友元函数可以是一个普通函数 也可以其它类中的一个成员函数 它不是本类的成员函数 但它可以访问本类的私有成员和保护成员 友元函数需要在类的内部进行声明 格式如下 class类名称 类的成员声明friend返回类型友元函数名 参数列表 类的成员声明 2 友元函数 7友元 90 例 使用友元函数计算两点间的距离 include includeclassPoint 定义Point类 点 public Point doublexx doubleyy 构造函数 x xx y yy voidGetxy 成员函数声明frienddoubleDistance Point 7友元 91 voidPoint Getxy 成员函数实现cout x y 输出点的坐标 doubleDistance Point 调用友元函数 7友元 92 实例说明 程序在类定义体内声明了友元函数的原形 在声明时函数名前加friend关键字进行修饰 友元函数的具体实现在类外给出 可以看出友元函数通过对象名可直接访问Point类的私有成员 而不需要借用外部接口Getxy 在调用友元函数时同调用普通函数一样 采用直接调用方法 而不需要像调用类的成员函数那样必须通过对象 程序的输出结果为 3 4 6 8 Thedistanceis5 7友元 93 友元函数例 94 说明 1 友元函数不是类的成员函数 因此在外部定义友元函数时 不必加类名 2 友元函数一般带有一个该类的入口参数 并做成对象引用或指针的方式 如 voiddisp girl x 一个友元函数还可以做成多个类的友元 能够访问相应的所有类的数据 例 友元函数破坏了数据的隐蔽性 降低程序的可维护性 应该谨用 95 3 友元类 同函数一样 类也可以声明为另一个类的友元 这时称为友元类 当一个类作为另一个类的友元时 这个类的所有成员函数都将是另一个类的友元函数 友元类的一般格式为 class类A 类A的成员声明friendclass类B 类A的成员声明 7友元 96 例 includeclassA 定义类A public A intxx intyy 类A的构造函数 x xx y yy friendclassB 声明类B为类A的友元类private intx y classB 定义类B public voiddisp1 As cout disp1调用了类A的私有成员x s x endl 类B的成员函数访问类A的私有成员 7友元 97 程序中定义了A和B两个类 其中类B为类A的友元类 定义时在类A的内部声明类B 而类B的具体实现过程是在类A的外部 类B中有两个成员函数disp1和disp2 根据友元类的概念 这两个成员函数都成为类A的友元函数 所以它们都可以访问类A的私有成员x和y 程序的输出结果为 disp1调用了类A的私有成员x

温馨提示

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

评论

0/150

提交评论