




已阅读5页,还剩69页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
面向对象程序设计概述 类和对象 带默认参数的函数和函数重载 构造函数和析构函数 对象成员和静态成员 友元 类模版和模版类 C 面向过程的程序设计 C语言 适用于规模比较小的程序 详细地描述每一瞬时的数据结构及对其的操作过程 但是当程序规模较大时 就显得力不从心了 C 就是为了解决编写大程序过程中的困难而产生的 面向对象的程序设计的思路类似于人们日常生活中处理问题的思路 在自然界和社会生活中 一个复杂的事物总是由许多部分组成 当人们生产汽车时 分别设计和制造发动机 底盘 车身和轮子 最后把它们组装在一起 在组装时 各部分之间有一定的联系 以便协调工作 这就是面向对象的程序设计的基本思路 下面先讨论几个有关的概念 9 1面向对象程序设计概述 1 对象对象是构成系统的基本单位 客观世界中任何一个事物都可以看成一个对象 object 任何一个对象都应当具有两个要素 即属性 attribute 和行为 behavior 一个系统的多个对象之间通过一定的渠道相互联系 如图9 1示意 要使某一个对象实现某一种行为 即操作 应当向它传送相应的消息 对象之间就是通过发送和接收消息互相联系的 图9 1图9 2 使用OOP方法设计一个复杂的软件系统时 首要的问题是确定该系统是由哪些对象组成的 并且设计这些对象 在C 中 每个对象都是由数据和函数这两部分组成的 见图9 2 数据体现了前面提到的 属性 如一个三角形对象 它的3个边长就是它的属性 函数体现了前面提到的 行为 如通过边长计算三角形面积和输出有关数据 调用对象中的函数就是向该对象传送一个消息 message 要求该对象实现某一行为 功能 2 封装与信息隐蔽面向对象程序设计方法的一个重要特点就是 封装性 encapsulation 所谓 封装 指两方面的含义 一是将有关的数据和操作代码封装在一个对象中 形成一个基本单位 各个对象之间相对独立 互不干扰 二是将对象中某些部分对外隐蔽 即隐蔽其内部细节 只留下少量接口 以便与外界联系 接收外界的消息 这种对外界隐蔽的做法称为信息隐蔽 imformationhiding 信息隐蔽还有利于数据安全 防止无关的人了解和修改数据 3 抽象 abstraction 抽象的过程是将有关事物的共性归纳 集中的过程 抽象的作用是表示同一类事物的本质 C和C 中的数据类型就是对一批具体的数的抽象 对象是具体存在的 如一个三角形可以作为一个对象 10个不同尺寸的三角形是10个对象 如果这10个三角形对象有相同的属性和行为 可以将它们抽象为一种类型 称为三角形类型 在C 中 这种类型就称为 类 class 这10个三角形就是属于同一 类 的对象 类是对象的抽象 而对象则是类的实例 或者说是类的具体表现形式 4 继承与重用如果在软件开发中已经建立了一个名为A的 类 又想另外建立一个名为B的 类 而后者与前者内容基本相同 只是在前者的基础上增加一些属性和行为 只需在类A的基础上增加一些新内容即可 这就是面向对象程序设计中的继承机制 利用继承可以简化程序设计的步骤 白马 继承了 马 的基本特征 又增加了新的特征 颜色 马 是父类 或称为基类 白马 是从 马 派生出来的 称为子类或派生类 C 提供了继承机制 采用继承的方法可以很方便地利用一个已有的类建立一个新的类 这就是常说的 软件重用 softwarereusability 的思想 5 多态性如果有几个相似而不完全相同的对象 有时人们要求在向它们发出同一个消息时 它们的反应各不相同 分别执行不同的操作 这种情况就是多态现象 如 在Windows环境下 用鼠标双击一个文件对象 这就是向对象传送一个消息 如果对象是一个可执行文件 则会执行此程序 如果对象是一个文本文件 则启动文本编辑器并打开该文件 在C 中 所谓多态性 polymorphism 是指 由继承而产生的相关的不同的类 其对象对同一消息会作出不同的响应 多态性是面向对象程序设计的一个重要特征 能增加程序的灵活性 类是C 实现面向对象程序设计的基础 类是所有面向对象的语言的共同特征 所有面向对象的语言都提供了这种类型 程序设计者的任务包括两个方面 一是设计所需的各种类和对象 即决定把哪些数据和操作封装在一起 二是考虑怎样向有关对象发送消息 以完成所需的任务 9 1 2类和对象的作用 与面向过程的程序不同 基于对象的程序是以类和对象为基础的 程序的操作是围绕对象进行的 在此基础上利用了继承机制和多态性 就成为面向对象的程序设计 在面向过程的结构化程序设计中 人们常使用这样的公式来表述程序 程序 算法 数据结构 面向过程的程序设计是以算法为主体的 面向对象程序设计把一个算法和一组数据结构封装在一个对象中 形成了新的观念 对象 算法 数据结构程序 对象 对象 对象 消息消息的作用就是对对象的控制 程序设计的关键是设计好每一个对象 及确定向这些对象发出的命令 使各对象完成相应操作 抽象 抽象是对具体对象 问题 进行概括 抽出这一类对象的公共性质并加以描述的过程 先注意问题的本质及描述 其次是实现过程或细节 数据抽象 描述某类对象的属性或状态 对象相互区别的物理量 代码抽象 描述某类对象的共有的行为特征或具有的功能 抽象的实现 通过类的声明 OOP的基本特点 要设计一个类 首先要对需处理的问题进行抽象 抽象实例 钟表 数据抽象 intHour intMinute intSecond代码抽象 SetTime ShowTime 钟表类 OOP的基本特点 classClock public voidSetTime intNewH intNewM intNewS voidShowTime private intHour Minute Second 封装 将抽象出的数据成员 代码成员相结合 将它们视为一个整体 目的是增强安全性和简化编程 使用者不必了解具体的实现细节 而只需要通过外部接口 以特定的访问权限 来使用类的成员 实现封装 类声明中的 OOP的基本特点 封装 实例 classClock public voidSetTime intNewH intNewM intNewS voidShowTime private intHour Minute Second OOP的基本特点 一 什么是类 类是对某一类对象的抽象 类是将不同类型的数据和与这些数据相关的操作封装在一起的集合体 因此 类具有更高的抽象性 类中的数据具有隐藏性 类还具有封装性 9 2 1类的定义 9 2类和对象 类是一种用户定义的类型 C 语言中提供了类这种工具使得应用中的实体 对象 在程序中可以直接地被表示为一个标识符 并且可以对它进行引用和操作 类的结构是用来确定一类对象的行为的 而这些行为是通过类的内部数据结构和相关的操作来确定的 二 类的定义格式 类的定义格式一般地分为说明部分和实现部分 说明部分是用来说明该类中的成员 包含数据成员的说明和成员函数的说明 实现部分是对成员函数的定义 概括说来 说明部分将告诉使用者 干什么 而实现部分是告诉使用者 怎么干 类的一般定义格式如下 class public private protected class是关键字 不能省略 标志符 一般情况下 类名的第一个字母大写 以区别于普通的变量和对象 分号不能丢 公有的成员用public说明 公有部分往往是一些操作 即成员函数 这部分成员可以在程序中被引用 它提供了一个类的接口 1 类的成员包括数据成员和成员函数两部分 从访问权限上来分 类的成员又分为 公有的 public 私有的 private 和保护的 protected 三类 一般情况下 先定义公有成员 再定义保护成员和私有成员 私有成员用private说明 私有部分通常是一些数据成员 这些成员是用来描述该类中的对象的属性的 用户无法访问它们 只有成员函数或经特殊说明的函数才可以引用它们 它们是被隐藏的部分 保护成员用protected说明 保护成员具有公有成员和私有成员的双重角色 对派生类的成员函数而言 它是公有成员 即派生类的成员函数可以访问基类的保护成员 但对在类之外定义的其它函数或类的对象而言 则是私有成员 2 关键字public private和protected在类体内出现的先后顺序无关 并且允许多次出现 用它们来说明类成员的访问权限 缺省的访问权限是私有的 private 3 是类定义中的实现部分 这部分包含所有在类体内说明的函数的定义 如果一个成员函数在类体内定义了 实现部分将不出现 如果所有的成员函数都在类体内定义了 则实现部分可以省略 4 类具有封装性 C 中的数据封装通过类来实现 外部不能访问说明为private和protected的成员 5 结构和类的区别在于 在默认的情况下 结构体中的数据成员和成员函数都是公有的 而在类中是私有的 在所有其它方面 结构和类等价 尽管如此 一般我们仅在描述数据成员时使用结构 当既有数据成员又有成员函数时使用类 给出一关于日期类的定义 classTdate 定义日期类 public 定义公有成员函数voidSetdate inty intm intd intLeap voidPrint private 定义私有数据成员intyear month day 类定义体结束 类的数据成员说明对象的特征 而成员函数决定对象的操作行为 成员函数是程序算法实现部分 是对封装的数据进行操作的唯一途径 类的成员函数有两种定义方法 外联定义和内联定义 成员函数的定义 2 1 外联函数 在类定义体中声明成员函数 而在类外定义成员函数 在类中声明成员函数时 它所带的函数参数可以只指出其类型 在类外定义成员函数时必须在函数名前缀上类名 在函数名和类名之间加上作用域分隔符 在类外定义成员函数的具体形式为 返回值类型 形式参数表 函数体 如上例中的三个成员函数分别定义如下 voidTdate Setdate inty intm intd year y month m day d intTdate Leap return year 4 0 内联函数是指程序在编译时将函数的代码插入在函数的每个调用处 作为函数体的内部扩展 用来避免函数调用机制所带来的开销 提高程序的执行效率 内联函数有两种定义方法 一 将成员函数的实现写在类体内 二 使用inline关键字 2 内联成员函数 内部函数 内置函数 1 在类体内定义内联函数 classTdate public Tdate voidSetdate inty intm intd year y month m day d intLeap return year 4 0 2 使用关键字inline定义内联函数 inlinevoidTdate Set intm intd inty 置日期值 year y month m day d 或voidinlineTdate Set intm intd inty 置日期值 year y month m day d 三 注意 类体中不允许对所定义的数据成员进行初始化 classTdate public private intyear 1998 month 4 day 8 是错误的 对象是类的实例 是由数据及其操作所构成的封装体 对象是属于某个已知的类 因此 在定义对象之前 一定要先定义好该对象所属的类 对象的定义 3 一 对象的定义方式 1 在定义类的同时直接定义 classLocation private intx y public voidinit intx0 inty0 intGetx void intGety void dot1 dot2 2 在使用时定义对象 Tdatedate1 date2 pdate date3 date1 data 31 其中 Tdate为日期类的类名 date1和date2是一般的对象名 pdate是指向对象的指针 date3是对象的引用 给它赋以初值 使它是date1的别名 date是对象数组的数组名 它有31个元素 每个元素是一个对象 类名标志符 标志符 Locationdot1 dot2 二 成员的访问 1 一般对象的成员表示 对象名 公有成员名 表示数据成员 或 对象名 公有成员名 参数表 表示成员函数 这里 是成员运算符 该运算符的功能是表示对象的成员 date1 year表示Tdate类的date1对象的year成员 date1 Setdate inty intm intd 表示Tdate类的date1对象的成员函数Setdate 2 指向对象的指针的成员表示 对象指针名 公有成员名 对象指针名 公有成员名 这里 是指向运算符 它与 运算符的区别是 用来表示指向对象的指针的成员 而 用来表示一般对象的成员 注意 只有用public定义的公有成员才能使用圆点操作符访问 对象中的私有成员是类中隐藏的数据 不允许在类外的程序中被直接访问 只能通过该类的公有成员函数来访问它们 classMyclock private inthour minute second public voidinit voidupdate voiddisplay Myclockclock pclock clock init 通过对象访问公有成员函数pclock 错误 因为对象不能访问其私有成员 3 引用对象的成员表示与一般对象的成员表示相同 date3是date1的Tdate类的引用 它的成员表示如下 date3 year date3 Setdate 等 分析下列程序的输出结果 include iostream h classTdate public Tdate voidSetdate inty intm intd year y month m day d intLeap return year 4 0 voidmain Tdatedate1 date2 date1 Setdate 1996 5 4 date2 Setdate 1998 4 9 intleap date1 Leap cout leap endl date1 Print date2 Print 运行结果 11996 5 41998 4 9 一 名字解析 在调用成员函数时 通常使用缩写的形式 如课本P175的clock init 就是clock Myclock init 的缩写 可以定义两个或多个类的具有相同名字的成员而不会产生二义性 名字解析和this指针 3 二 this指针 this指针是一个隐含于每一个成员函数中的特殊指针 当对一个对象调用成员函数时 编译程序先将对象的地址赋给this指针 然后调用成员函数 每次成员函数存取数据成员时 都隐含作用this指针 而通常不去显式地使用this指针来引用数据成员 在程序中可以用this关键字来引用该指针 this指针的类型就是成员函数所属的类的类型 当调用成员函数时 它被初始化为被调用函数所在的类实例的地址 举例见课本P176 由于不同的对象调用成员函数时 this指针指向不同的对象 因此同一个成员函数可以为不同的对象赋初值 使用this指针 保证了每个对象可以拥有不同的数据成员 但处理这些数据成员的代码可以被所有对象共享 9 3带默认参数的函数和函数重载 1 带默认参数的函数 如果在函数说明或函数定义中为形参指定一个默认值 则称此函数为带默认参数的函数 如果在调用时指定了形参相对应的实参 则形参使用实参的值 如果未指定相应的实参 则形参使用默认值 例 voidinit intx 4 如果调用语句init 10 则传递给形参的值为10 如果调用语句为init 则传递给形参的值为4 默认参数 如果函数有多个默认参数 则默认参数必须从右向左定义 并且在一个默认参数的右边不能有未指定默认值的参数 例如 voidfun inta intb 1 intc 4 intd 5 voidfun inta 3 intb 6 intc intd voidfun inta 65 intb 3 intc intd 3 例9 1 带默认参数的函数 includeclassTdate pubic voidSet intm 5 intd 16 inty 1991 month m day d year y voidPrint cout month day year endl private intmonth intday intyear voidmain Tdatea b c a Set 4 12 1996 b Set 3 c Set 8 10 a Print b Print c Print 运行结果 4 12 19963 16 19918 10 1991 2 函数重载 C 语言编译系统允许为两个或两个以上的函数取相同的函数名 但是形参的个数或者形参的类型不应相同 编译系统会根据实参和形参的类型及个数的最佳匹配自动确定调用哪一个函数 这就是所谓的函数重载 函数重载使函数方便使用 便于记忆 也使程序设计灵活 增加了程序的可读性 函数重载无需特别声明 只要所定义的函数与已经定义的同名函数形参形式不完全相同即可 includeintmax inta intb if a b returna elsereturnb floatmax floata floatb if a b returna elsereturnb char max char a char b if strcmp a b 0 returna elsereturnb voidmain intx floaty char z x max 2 3 y max 2 4f 3 6f z max ab efg cout x y z endl 三个同名函数返回值类型及形参类型不同 除此之外 还可以参数个数不同 例9 2 重载函数应用举例 includeintadd intx inty intsum sum x y returnsum intadd intx inty intz intsum sum x y z returnsum voidmain inta b a add 5 10 b add 5 10 20 cout a a endl cout b b endl 运行结果 a 15b 35 在使用重载函数时要注意以下两点 1 不可以定义两个具有相同名称 相同参数类型和相同参数个数 只是函数返回值不同的函数 例如 intfunc intx floatfunc intx 2 如果某个函数参数有默认值 必须保证其参数默认后不与其它函数混淆 例如 intf inta floatb floatf inta floatb intc 0 函数调用语句f 10 2 0 具有二义性 不能确定到底调用哪个函数 错误 错误 一 构造函数 功能 创建对象时 使用给定值将对象初始化 C 提供了一种特殊的成员函数 构造函数 constructor 这种函数不需要用户发 消息 来激活它 而是在建立对象时由系统自动执行 构造函数是由用户定义的 它必须与类名同名 以便系统能识别它并把它作为构造函数 构造函数和析构函数 9 4 构造函数的特点 1 构造函数是成员函数 函数体可写在类体内 也可写在类体外 2 构造函数是一个特殊的函数 该函数的名字与类名相同 一般声明为public函数 无返回值 不指定类型 也不需要加void类型声明 3 构造函数可以重载 即可以定义多个参数个数或参数类型不同的构造函数 4 程序中不能直接调用构造函数 在创建对象时系统自动调用构造函数 5 在类定义时没有定义构造函数时 编译系统会自动生成一个默认构造函数 用默认构造函数对对象初始化时 将全局对象或静态对象的所有数据成员都初始化为零或空 其它对象值是随机的 只要一个类定义了一个构造函数 不一定是无参构造函数 C 就不再提供缺省的构造函数 即如果为类定义了带参数的构造函数 还想要无参构造函数 则必须自己定义 给构造函数提供缺省参数的好处是 即使在调用构造函数的时候没有提供参数值 也会确保按照缺省的参数值对对象进行初始化 例9 3 构造函数的定义 使用和重载 includeclasstest private intnum floatf1 public test test intn floatf intgetint returnnum floatgetfloat returnf1 test test cout Initializingdefault endl num 0 f1 0 0 test test intn floatf cout Initializing n f endl num n f1 f voidmain void testx testy 10 21 5 运行结果为 InitializingdefaultInitializing10 21 5 例9 4 带默认参数的构造函数 includeclassTdate public Tdate intm 5 intd 16 inty 1990 month m day d year y cout month day year endl private intmonth intday intyear voidmain Tdateaday Tdatebday 2 Tdatecday 3 12 Tdatedday 1 2 1998 运行结果为 5 16 19902 16 19903 12 19901 2 1998 使用带默认参数的构造函数时 要注意避免二义性 所带的参数个数或参数类型必须有所不同 否则系统调用时会出现二义性 例9 5 默认构造函数 includeclassStudent public Student char pName strncpy name pName sizeof name name sizeof name 1 0 Student 不能省略 因为在main 中创建无参对象noName时使用protected charname 20 voidmain StudentnoName Studentss Jenny 常见的程序设计错误 在定义类的时候试图初始化数据成员 类的数据成员必须在类的构造函数中初始化 或者在建立类的对象后再设置它们的值 试图声明构造函数的返回值类型 或试图从构造函数返回一个值 复制构造函数 复制构造函数是一种特殊的成员函数 其形参是本类对象的引用 它的功能是用一个已知的对象来初始化一个被创建的同类的对象 复制构造函数实际上也是构造函数 它是在初始化时被调用来将一个已知对象的数据成员的值拷贝给正在创建的另一个同类的对象 其特点如下 1 该函数名同类名 并且该函数也不被指定返回类型 2 该函数只有一个参数 并且是对某个对象的引用 3 每个类都有各自的复制构造函数 其格式如下所示 类名 类名 类名 引用名 4 如果类中没有说明复制构造函数 则编译系统自动生成一个具有上述形式的默认复制构造函数 作为该类的公有成员 复制构造函数 复制构造函数是一种特殊的构造函数 其形参为本类的对象引用 class类名 public 类名 形参 构造函数类名 类名 对象名 复制构造函数 类名 类名 类名 对象名 复制构造函数的实现 函数体 构造函数和析构函数 复制构造函数 classcat private intage floatweight char color public cat cat cat 复制构造函数举例 classPoint public Point intxx 0 intyy 0 X xx Y yy Point Point 构造函数和析构函数 复制构造函数调用 当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现拷贝赋值 voidmain void PointA 1 2 PointB A 复制构造函数被调用cout B GetX endl 构造函数和析构函数 复制构造函数调用 若函数的形参为类对象 调用函数时 实参赋值给形参 系统自动调用复制构造函数 例如 voidfun1 Pointp cout p GetX endl voidmain PointA 1 2 fun1 A 调用复制构造函数 构造函数和析构函数 复制构造函数调用 当函数的返回值是类对象时 系统自动调用复制构造函数 例如 Pointfun2 PointA 1 2 returnA 调用复制构造函数 voidmain PointB B fun2 构造函数和析构函数 构造初始化表 构造函数也可以使用构造初始化表对数据成员进行初始化 Circle Circle floatr radius r 可改写为 Circle Circle floatr radius r 对于类的数据成员是一般变量的情况 那么无论是放在冒号后面还是放在函数体中 其初始化都一样 常量和引用的初始化必须放在构造函数的冒号后面 成员初始化的次序取决于它们在类定义中的声明次序 与它们在成员初始化表中的次序无关 二 析构函数 功能 用来释放一个对象 析构函数 destructor 与构造函数相反 当对象脱离其作用域时 如 对象所在的函数已调用完毕 系统自动执行析构函数 将对象所占内存空间释放 析构函数的特点 1 析构函数也是成员函数 函数体可写在类体内 也可以写在类体外 2 析构函数的名字同类名 并在前面加 字符 用来与构造函数加以区别 析构函数不指定数据类型 并且也没有参数 没有返回值 3 一个类中只可能定义一个析构函数 不能重载 4 析构函数可以被调用 也可以系统自动调用 在下面两种情况 析构函数会被自动调用 如果一个对象被定义在一个函数体内 则当这个函数结束时 该对象的析构函数被自动调用 当一个对象是用new运算符被动态创建的 在使用delete运算符释放它时 delete会自动调用析构函数 5 如果用户没有编写析构函数 编译系统会自动生成一个缺省的析构函数 6 析构函数与构造函数的调用顺序相反 例9 7 析构函数和构造函数的调用顺序 include includeclassStudent public Student char pName noname intssId 0 strncpy name pName 40 name 39 0 id ssId cout Constructingnewstudent pName endl Student Student 例9 7 析构函数和构造函数的调用顺序 Student cout Destructing name endl protected charname 40 intid voidfn Students cout Infunctionfn n voidmain Studentrandy Randy 1234 Studentwang Wang 5678 cout Callingfn n fn randy 调用fn函数 参数传递时调用复制构造函数cout Returnedfromfn n 主函数调用结束时 先析构对象Wang 再析构对象Randy 运行结果为 ConstructingnewstudentRandyConstructingnewstudentWangCallingfn ConstructingcopyofRandyInfunctionfn DestructingcopyofR
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 多方合作研发新药协议
- 护理法律案例分析讨论
- 2025杂志销售合同范本
- 2025年新型环保预制混凝土构件加工与供应合同范本
- 2025年度科研创新项目跟踪与成果转化合同
- 2025年版权转让合同:某文学作品版权交易案例
- 农民种植技术培训与服务合同
- 电厂年度述职报告
- 森林摄影基地创新创业项目商业计划书
- 水的奥秘课件
- GB 23466-2025听力防护装备的选择、使用和维护
- 2025年全国保密教育线上培训考试试题库完整答案附带答案详解
- 全套教学课件《工程伦理学》
- 国家中长期科技发展规划纲要2021-2035
- 高级食品微生物学- 课件全套 第1-9章 益生菌的分类、分离与鉴定-微生物的系统生物学研究技术
- 产品报价单货物报价表(通用版)
- 计算机专业英语第4版PPT完整全套教学课件
- 国防法规优秀课件
- 世界烟草控制框架公约解读
- GB/T 1631-2008离子交换树脂命名系统和基本规范
- 清洗地毯操作流程课件
评论
0/150
提交评论