3 类和对象(一)_第1页
3 类和对象(一)_第2页
3 类和对象(一)_第3页
3 类和对象(一)_第4页
3 类和对象(一)_第5页
已阅读5页,还剩103页未读 继续免费阅读

下载本文档

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

文档简介

第3章类和对象 一 3 1类的构成3 2成员函数的定义3 3对象的定义和使用3 4构造函数与析构函数 3 1类的构成 主要内容 3 1 1从结构体到类3 1 2类的构成 3 1 1从结构体到类1 结构体的扩充 C语言结构体一般格式如下 struct结构名 类型成员数据 例如下面声明了一个日期结构体 structDate intyear 年intmonth 月intday 日 例3 1有关日期结构体的例子 includeusingnamespacestd structDate 声明了一个名为Date的结构体intyear intmonth intday intmain Datedate1 date1 year 2010 可以在结构体外直接访问数据yeardate1 month 8 可以在结构体外直接访问数据monthdate1 day 25 可以在结构体外直接访问数据daycout date1 year date1 month date1 day endl return0 程序的运行结果如下 2010 8 25 C语言中的结构体缺点 结构体变量可以在结构体外直接访问数据 在C结构体中的数据是很不安全的 C 中引入了类的概念 克服了C结构体的缺点 C 中引入了类的概念 它不仅可以含有数据 而且还可以含有函数 类中的数据和函数 分别称作数据成员和成员函数 类声明的简化格式如下 class类名 数据函数 类的声明由关键字class打头 后跟类名 花括号中是类体 以一个分号 结束 类声明的简化格式如下 class类名 数据成员函数函数 3 1 2类的构成在类中 数据成员和成员函数分别属于private部分 protected部分和public部分 数据成员和成员函数一般也统称为类的成员 类声明的一般格式如下 class类名 public 公有数据成员 公有成员函数 protected 保护数据成员 保护成员函数 private 私有数据成员 私有成员函数 公有成员既可被类内的成员函数访问 也可被类的外部访问 是类与外界的接口 私有成员只能被类内的成员函数访问 而类外部的任何访问都是非法的 保护成员可以由本类的成员函数访问 也可以由本类的派生类的成员函数访问 而类外的任何访问都是非法的 将在第5章详细介绍 2 类的定义格式 类的定义格式一般分为说明部分和实现部分 说明部分 是用来说明类中的成员 包含数据成员的说明和成员函数的说明 成员函数是用来对数据成员进行操作的 也称为 方法 实现部分 是用来对成员函数进行定义 说明部分的一般格式为 class类类型名 private 私有成员说明public 公有成员说明 程序中的任何函数都可访问 私有访问权限 为默认值 可缺省 除本类中的成员函数及友元外 其他类外函数不能访问 公有访问权限 例如 定义一个person类 设person具有的特征 属性 姓名 年龄 性别 方法 输出一个人的属性 则对应着有4个成员 三个数据成员 一个成员函数 这些数据成员一般不能由外界直接访问 随意修改 而只能通过成员函数进行访问 所以三个数据成员定义为私有成员 print成员函数定义为公有成员 则有 classTperson private charname 10 intage charsex public voidprint 成员函数的说明形式与一般函数的说明形式一致 数据成员的说明形式与变量的定义形式相似 类名通常用T字母开始 以区别其他标识符 类的实现部分即定义它的成员函数 方式与定义普通函数大体相同 若在类说明外部定义成员函数 则应使用作用域限定符 指明该函数是哪个类中的成员函数 格式为 类型类名 成员函数名 参数表 函数体 如 voidTperson print cout name age sex endl 除特殊指明外 成员函数操作的是同一对象中的数据成员 其中如name等 若在成员函数中调用非成员函数 没有类名的函数 全局函数 则可用不带类名的 来表示 当成员函数的规模较小时 语句只有1 5行 符合内联函数条件 则可在类中定义成员函数 成为内联成员函数 如 classTDate public voidSet intm intd inty 置日期值 month m day d year y voidPrint 打印输出private intmonth intday intyear 由于类名是成员函数名的一部分 所以一个类的成员函数与另一个类的成员函数可同名 若将内联成员函数定义在类说明之外则要加上inline 内联成员函数 注意 3 注意事项 1 在类体中不允许对所定义的数据成员进行初始化 classTDate public private intyear 1998 month 4 2 类中的数据成员的类型可以为任意的 3 习惯将类的定义代码放到一个头文件中 以后若要使用则用文件包含命令包含 错误 如定义一个类 classTPoint public voidSetPoint intx inty 置坐标值 X x Y y 给数据成员赋值 intXcoord returnX 提供X坐标值intYcoord returnY 提供Y坐标值voidMove intxOffset intyOffset 移动点private intX intY voidTpoint Move intxOffset intyOffset X xOffset Y yOffset 类体外成员函数的定义 内联成员函数的定义 私有数据成员的定义 4 关于类定义的若干说明如下 定义类的关键字通常用class 也可以用struct等 类的定义由两大部分构成 说明部分和实现部分 类的成员分为数据成员和成员函数两种 类的成员具有访问权 类成员的访问权限有如下3种 public 公有的 公有成员不仅在类体内是可见的 而且在类体外也是可见的 private 私有的 私有成员仅在类体内是可见的 在类体外是被隐藏的 protected 保护的 保护成员对于定义它的类来讲 相当于私有成员 对于该类的派生类来讲 相当于公有成员 成员函数可以定义在类体内 也可以定义在类体外 用一个类TDate来描述日期 其形式如下 classTDate public voidsetDate inty intm intd 公有成员函数voidshowDate 公有成员函数private intyear 私有数据成员intmonth 私有数据成员intday 私有数据成员 私有数据成员year month和day只能由内部成员函数访问 在类的外部无法访问 保护了私有数据的安全 设置日期成员函数setDate和日期显示成员函数showDate都是公有的成员函数 类外部对类Date的数据进行操作 只能通过这两个函数来实现 3 2成员函数的定义3 2 1普通成员函数的定义3 2 2内联成员函数的定义 3 2 1普通成员函数的定义将成员函数以普通成员函数 即非内联的成员函数 的形式进行定义 在类声明中只给出成员函数的原型 而将成员函数的定义放在类外部 例如 Student 成员函数名 参数表 成员函数在类外定义的一般形式是 返回值类型类名 成员函数名 参数表 函数体 在类名和成员函数名之间应加上作用域运算符 classStudent 学生类的定义 1private intnumber floatscore public voidinput intnumber1 floatscore1 函数原型1 输入成绩voidmodify floatscore1 函数原型2 修改成绩voidprint 函数原型3 打印成绩 voidStudent input intnumber1 floatscore1 函数定义1 number number1 score score1 voidStudent modify floatscore1 函数定义2 score score1 voidStudent print 函数定义3 cout nnumber number score score 在类声明中只给出成员函数的原型 而将成员函数的定义放在类外部 在函数名前应加上类名和作用域运算符 说明 1 在类声明中 成员函数原型的参数表中可以不说明参数的名字 而只说明它们的类型 例如 voidmodify float 但是 在类外定义成员函数时 不但要说明参数表中参数的类型 还必须要指出其参数名 例如 voidStudent modify floatscore1 score score1 2 采用 在类声明中只给出成员函数的原型 而将成员函数的定义放在类的外部 的定义方式 是C 程序设计的良好习惯 3 2 2内联成员函数的定义 1 隐式声明将成员函数直接定义在类的内部 例如 classStudent 学生类的定义 2private intnumber floatscore public voidinput intnumber1 floatscore1 定义成员函数 number number1 score score1 voidmodify floatscore1 定义成员函数 score score1 voidprint 定义成员函数 cout nnumber number score score 将成员函数直接定义在类内部 编译时是作为内联函数的方式来处理 内联函数隐式定义 2 显式声明在类声明中只给出成员函数的原型 而成员函数的定义放在类外部 但在类外部成员函数的定义前冠以关键字 inline 使它起到内联函数的作用 classStudent private intnumber floatscore public voidinput intnumber1 floatscore1 inlinevoidStudent input intnumber1 floatscore1 number number1 score score1 成员函数的原型 冠以关键字 inline 使用inline定义内联函数时 可以在声明函数原型和定义函数时同时写inline 也可以在其中一处声明inline 效果是相同的 都能按内联函数处理 但是 必须将类的声明和内联成员函数的定义都放在同一个文件 或同一个头文件 中 否则编译时无法进行代码置换 classStudent 学生类的定义 3private intnumber floatscore public inlinevoidinput intnumber1 floatscore1 函数原型1inlinevoidmodify floatscore1 函数原型2inlinevoidprint 函数原型3 inlinevoidStudent input intnumber1 floatscore1 number number1 函数定义1score score1 inlinevoidStudent modify floatscore1 score score1 函数定义2inlinevoidStudent print 函数定义3 cout nnumber number score score 冠以关键字 inline 3 3对象的定义和使用3 3 1类与对象的关系3 3 2对象的定义3 3 3对象中成员的访问3 3 4类的作用域和类成员的访问属性3 3 5对象赋值语句 3 3 1类与对象的关系在C 中 类与对象间的关系 可以用数据类型int和整型变量i之间的关系来类比 类类型和int类型均代表的是一般的概念 而对象和整型变量却是代表具体的东西 3 3 2 对象的定义定义对象可以用以下两种方法 方法1 在声明类的同时 直接定义对象 即在声明类的右花括号 后 直接写出属于该类的对象名表 例如 classStudent stu1 stu2 在声明类Student的同时 直接定义对象stu1和stu2 方法2 声明了类之后 在使用时再定义对象 其一般形式如下 classStudent Studentstu1 stu2 在使用时再定义对象 此时定义了类Student的两个对象stu1和stu2 说明 声明了一个类便声明了一种类型 这时没有给它分配存储空间 只有定义了对象后 系统才为对象分配存储空间 类名对象名1 对象名2 3 3 3对象中成员的访问不论是数据成员 还是成员函数 只要是公有的 在类的外部可以通过类的对象进行访问 访问对象中的成员通常有以下三种方法 1 通过对象名和对象选择符访问对象中的成员其一般形式是 其中 叫做对象选择符 简称点运算符 对象名 数据成员名或对象名 成员函数名 实参表 include 例3 2 1usingnamespacestd classpoint private intx y public voidsetpoint inta intb x a y b intgetx returnx intgety returny voidmain pointop1 定义了类point的对象op1inti j op1 setpoint 1 2 调用op1的成员函数setpoint 初始化对象op1i op1 getx 调用op1的成员函数getx 取op1的x值j op1 gety 调用op1的成员函数gety 取op1的y值cout op1i i op1j j endl 程序运行结果如下 op1i 1op1j 2 include 分析运行结果usingnamespacestd classpoint private intx y 私有数据成员public voidinit inta intb x a y b intgetx returnx intgety returny voidmain pointop 定义了类point的对象opinti j op init 1 2 i op x j op y cout opx i opy j endl 错误 解决方法 原因 在类的内部所有成员之间都可以通过成员函数直接访问 但是类的外部不能访问对象的私有成员 include 分析运行结果usingnamespacestd classpoint private intx y 私有数据成员public voidinit inta intb x a y b intgetx returnx intgety returny voidmain pointop inti j op init 1 2 i op getx j op gety cout opx i opy j endl 替代i op x j op y 类外部的对象可以通过公有成员函数对私有成员进行间接访问 程序运行结果如下 opx 1opy 2 include 学生类的完整程序usingnamespacestd classStudent private intnumber floatscore public voidinput intnumber1 floatscore1 输入学生成绩voidmodify floatscore1 修改学生成绩voidprint 打印学生成绩 voidStudent input intnumber1 floatscore1 number number1 score score1 voidStudent modify floatscore1 score score1 voidStudent print cout nnumber number score score intmain Studentstu1 stu2 stu1 input 9901 95 stu2 input 9902 75 stu1 print stu2 print stu1 modify 85 5 stu1 print stu2 print return0 stu1 number 9901 stu1 score 95stu2 number 9902 stu2 score 75 stu1 score 85 5 运行结果 number 9901score 95number 9902score 75number 9901score 85 5number 9902score 75 2 通过指向对象的指针访问对象中的成员此时 访问此对象的成员时 不能用 操作符 而应使用 操作符 例如 classDate public intyear Dated ptr 定义对象d和指向类Date的指针变量ptrptr 输出ptr指向对象中的成员year d year ptr year三者是等价的ptr year 3 通过对象的引用访问对象中的成员如果为一个对象定义了一个引用 也就是为这个对象起了一个别名 例如 classDate public intyear Dated1 定义类Date的对象d1Date 输出对象d2中的数据成员year 由于d2是d1的引用 即d2和d1占有相同的存储单元 因此d2 year和d1 year是相同的 3 3 4类的作用域和类成员的访问属性所谓类的作用域就是指在类的声明中的一对花括号所形成的作用域 一个类的所有成员都在该类的作用域内 在类的作用域内 一个类的任何成员函数成员可以不受限制地访问该类中的其他成员 而在类作用域之外 对该类的数据成员和成员函数的访问则要受到一定的限制 有时甚至是不允许的 这主要与类成员的访问属性有关 类成员有二种访问属性 公有属性和私有属性 说明为公有的成员不但可以被类中成员函数访问 还可在类的外部 通过类的对象进行访问 说明为私有的成员只能被类中成员函数访问 不能在类的外部 通过类的对象进行访问 换一种说法 类内部的成员函数可以访问类的所有成员 没有任何限制 类外部的对象可以访问类的公有成员 不能访问类的私有成员 classSample private inti 私有成员public intj 公有成员voidset inti1 intj1 公有成员 i i1 类的成员函数可以访问类的私有成员ij j1 类的成员函数可以访问类的公有成员j intmain Samplea 定义类Sample的对象aa set 3 5 cout a i endl cout a j endl return0 非法 类Sample的对象a不能访问类的私有成员i 在类外 类Sample的对象a可以访问公有成员函数set 合法 类Sample的对象a能够访问类的公有成员j 分析以下程序段 3 3 5对象赋值语句变量之间可以进行赋值 inta b b a 同类型的对象之间也可以进行赋值 对象赋值的一般形式为 当一个对象赋值给另一个对象时 所有的数据成员都会逐位拷贝 对象名1 对象名2 include 例3 5usingnamespacestd classABC public voidinit inti intj a i b j voidshow cout a b endl private inta b intmain ABCo1 o2 o1 init 12 34 o2 o1 将对象o1数据成员的值赋给对象o2o1 show o2 show return0 o1 a 12o1 b 34 赋值后的作用 o2 a o1 a o2 b o1 b 运行结果 12341234 说明 1 在使用对象赋值语句进行对象赋值时 两个对象的类型必须相同 如对象的类型不同 编译时将出错 2 两个对象之间的赋值 仅仅是对其中的数据成员赋值 而不对成员函数赋值 3 两个对象之间的赋值 仅仅使这些对象中数据相同 而两个对象仍是分离的 4 对象赋值是通过默认赋值运算符函数实现的 有关赋值运算符函数将在第7章介绍 5 当类中存在指针时 使用默认的赋值运算符函数进行对象赋值 可能会产生错误 这个问题我们将在3 4 8节中分析 3 4构造函数与析构函数3 4 1构造函数3 4 2成员初始化列表3 4 3带默认参数的构造函数3 4 4析构函数3 4 5默认的构造函数和默认的析构函数3 4 6构造函数的重载3 4 7拷贝构造函数3 4 8浅拷贝和深拷贝 3 4 1构造函数与使用变量一样 对象时也应该 先定义 后使用 在定义对象时 对数据成员赋初值 称为对象的初始化 对象的初始化常采用以下两种方法 1 调用普通的成员函数来完成2 调用构造函数来完成 classDate public voidsetDate inty intm intd voidshowDate private intyear intmonth intday intmain Datedate1 date1 setDate 2010 4 28 return0 调用对象date1的公有成员函数setDate 给date1的私有数据成员赋初值 初始化后 Date1 year 2010Date1 month 4Date1 day 28 1 用普通成员函数对对象进行初始化 在建立对象时 采用构造函数给数据成员赋初值 通常有以下两种形式 形式1 类名对象名 实参表 这里的 类名 与构造函数名相同 实参表 是为构造函数提供的实际参数 2 用构造函数对对象进行初始化 构造函数是一种特殊的成员函数 它主要用于 1 为对象分配空间 2 为对象的数据成员进行初始化 3 其他指定的任务 include 例3 7 1usingnamespacestd classDate public Date inty intm intd 声明构造函数Date的原型voidshowDate private intyear intmonth intday Date Date inty intm intd 定义构造函数Date year y month m day d inlinevoidDate showDate cout year month day endl intmain Datedate1 2010 4 28 date1 showDate return0 3 定义类Date的对象date1 调用构造函数 给对象date1的数据成员赋初值 2 构造函数可以有任意类型的参数 但不能具有返回类型 1 构造函数的名字必须与类名相同 在建立对象时 采用构造函数对对象进行初始化 通常有以下两种形式 形式1 例如 Datedate1 2010 4 28 建立对象时 编译系统会自动地调用构造函数 对对象进行初始化 类名对象名 实参表 形式2 其一般语法形式为 例如 Date pdate newDate 2010 4 28 类名 指针变量名 new类名 实参表 指针pdate指向该对象的地址对象名 匿名对象 或称对象名是 pdate 此时 应使用 来访问对象的成员 而不是 类名 指针变量名 new类名 实参表 将例3 7 1的主函数改成用这种方法来实现 intmain Date pdate newDate 2010 4 28 pdate showDate deletepdate return0 利用构造函数创建对象的另一种方法 用指针和new来实现 说明 1 构造函数的名字必须与类名相同 否则编译程序将把它当作一般的成员函数来处理 2 构造函数没有返回值 在声明和定义构造函数时 是不能说明它的类型的 甚至说明为void类型也不行 例如上述构造函数不能写成voidDate inty intm intd 说明为void类型也不行 3 与普通的成员函数一样 构造函数的函数体可写在类体内 也可写在类体外 如例3 7 1中的类Date可以声明如下 classDate public Date inty intm intd 构造函数定义在类内 year y month m day d voidshowDate cout year month day endl private intyear intmonth intday 构造函数的函数体也可写在类体外 4 构造函数一般声明为公有成员 但它不需要也不能像其他成员函数那样被显式地调用 它是在定义对象的同时被自动调用的 例如 下面的用法是错误的 date1 Date 2010 4 28 5 构造函数可以是不带参数的 例如 classAB private inta public AB a 10 intmain ABab 构造函数可以不带参数 定义类AB的对象ab时调用不带参数的构造函数给数据成员a赋初值10 3 4 2成员初始化列表 classA inti floatf public A inti1 floatf1 i i1 f f1 classA inti floatf public A inti1 floatf1 i i1 f f1 在构造函数中一般用赋值语句对数据成员的初始化进行 C 还提供另一种初始化数据成员的方法 用成员初始化列表来实现对数据成员的初始化 带有成员初始化列表的构造函数的一般形式如下 成员初始化列表的一般形式为 说明 1 在C 中某些类型的成员是不允许在构造函数中用赋值语句直接赋值的 例如 对于用const修饰的数据成员 或是引用类型的数据成员 是不允许用赋值语句直接赋值的 因此 只能用成员初始化列表对其进行初始化 类名 构造函数名 参数表 成员初始化列表 构造函数体 数据成员名1 初始值1 数据成员名2 初始值2 include 例3 8usingnamespacestd classA public A intx1 x x1 rx x pi 3 14 voidprint cout x x rx rx pi pi endl private intx int 用成员初始化列表对引用类型的数据成员rx和const修饰的的数据成员pi初始化 程序的运行结果如下 x 10rx 10pi 3 14 rx是整型变量的引用 pi是用const修饰的常量 2 数据成员是按照它们在类中声明的顺序进行初始化的 与它们在成员初始化列表中列出的顺序无关 练习1写出以下程序的运行结果 includeusingnamespacestd classD intmem1 intmem2 public D inti mem1 i mem2 mem1 1 cout mem1 mem1 endl cout mem2 mem2 endl voidmain Dd 15 相当于 mem1 i mem2 mem1 1 运行结果为 mem1 15mem2 16 includeusingnamespacestd classD intmem1 intmem2 public D inti mem2 i mem1 mem2 1 cout mem1 mem1 endl cout mem2 mem2 endl voidmain Dd 15 相当于 mem2 i mem1 mem2 1 请问 运行结果 mem1 16mem2 15实际运行结果 mem1 858993459mem2 15 原因 不是按照构造初始化表的顺序对数据成员进行初始化 而是按照数据成员在类里被声明的顺序进行初始化 练习2 includeusingnamespacestd classD intmem1 intmem2 public D inti mem2 i mem1 mem2 1 cout mem1 mem1 endl cout mem2 mem2 endl voidmain Dd 15 初始化过程 1 mem1 mem2 1 随机数2 mem2 i 15 程序结果如下 mem1 858993459mem2 15 解决方法 练习2 分析错误原因 练习2 includeusingnamespacestd classD intmem2 intmem1 public D inti mem2 i mem1 mem2 1 cout mem1 mem1 endl cout mem2 mem2 endl voidmain Dd 15 将mem1和mem2交换 运行结果为 mem1 16mem2 15 3 4 3带默认参数的构造函数 3 1 在实际使用中 有些构造函数的参数值在大部分情况是相同的 只有在特殊情况下才需要改变它的参数值 例如大学本科的学制一般默认为4年 某大学工科的学费一般默认为每年5000元 计时器的初始值一般默认为0等 这时可以将其定义成带默认参数的构造函数 例如长方体的长 宽 高的默认值均为10 其构造函数的原型可写成 Box inth 10 intw 10 intlen 10 调用此函数时 若省略其中某一实参 C 自动地以默认值作为相应参数的值 include 例3 10 1classBox private intheight width length public Box inth 10 intw 10 intlen 10 intvolume Box Box inth intw intlen height h width w length len intmain Boxbox1 cout box1 box1 volume endl Boxbox2 15 cout box2 box2 volume endl Boxbox3 15 30 cout box3 box3 volume endl Boxbox4 15 30 20 out box4 box4 volume endl return0 含有默认参数的构造函数 在此不再指定参数的默认值 不传递参数 全部用默认值 传递三个参数 只传递一个参数 传递两个参数 运行结果 box1 1000box2 1500box3 4500box1 9000 说明 在一个类中定义了全部是默认参数的构造函数后 不能同时再声明无参数的默认构造函数 或其他重载构造函数 例如在一个类中有以下构造函数的声明 Complex doubler 0 0 doublei 0 0 就不能再声明无参数的构造函数 Complex 否则 如用下面的语句建立对象ComplexS1 编译系统将无法判断应该调用哪个构造函数 因此产生了二义性 声明全部是默认参数的构造函数 3 4 4析构函数析构函数也是一种特殊的成员函数 它执行与构造函数相反的操作 通常用于执行一些清理任务 主要有 1 释放分配给对象的内存空间 2 其他指定的任务 classStudent 带构造函数的学生类private intnumber floatscore public Student intnumber1 floatscore1 Student cout destructing Student Student intnumber1 floatscore1 number number1 score score1 构造函数 析构函数 classStudent private intnumber floatscore public Student intnumber1 floatscore1 Student cout destructing Student Student intnumber1 floatscore1 number number1 score score1 析构函数与类名相同 但它前面必须加一个波浪号 析构函数没有参数 也没有返回值 当撤消对象时 编译系统会自动地调用析构函数 析构函数有以下一些特点 1 析构函数名与类名相同 但它前面必须加一个波浪号 2 析构函数不返回任何值 在定义析构函数时 是不能说明它的类型的 甚至说明为void类型也不行 3 析构函数没有参数 因此它不能被重载 一个类可以有多个构造函数 但是只能有一个析构函数 4 撤销对象时 编译系统会自动地调用析构函数 include 例3 11含有构造函数和析构函数的Date类 usingnamespacestd classDate public Date inty intm intd 声明构造函数 Date 声明析构函数voidsetDate inty intm intd voidshowDate private intyear intmonth intday Date Date inty intm intd 定义构造函数 cout constructing endl year y month m day d Date Date 定义析构函数 cout destruting endl voidDate setDate inty intm intd year y month m day d inlinevoidDate showDate cout year month day endl intmain Datedate1 2009 4 28 cout Date1output1 endl date1 showDatedate1 setDate 2009 11 14 cout Date1output2 endl date1 showDate return0 程序运行结果如下 constructing Date1output1 2009 4 28Date1output2 2009 11 14destruting 定义类Date的对象date1 调用date1的构造函数 初始化对象date1 例3 11 1下面我们重新说明complex类 使它既含有构造函数 又含有析构函数 include includeclasscomplex private doublereal doubleimag public complex doubler 0 0 doublei 0 0 声明构造函数 complex 声明析构函数doubleabscomplex complex complex doubler doublei 定义构造函数 cout constructing endl real r imag i complex complex 定义析构函数 cout destructing endl doublecomplex abscomplex doublet t real real imag imag returnsqrt t main complexA 1 1 2 2 cout absofcomplexA A abscomplex endl return0 程序运行结果如下 constructing absofcomplexA 2 45967destructing 说明 在以下情况 对象将被撤消 编译系统也会自动地调用析构函数 主程序main 运行结束 如果一个对象被定义在一个函数体内 则当这个函数结束时 该对象的析构函数被自动调用 若一个对象是使用new运算符动态创建的 在使用delete运算符释放它时 delete会自动调用析构函数 3 4 5默认的构造函数和默认的析构函数1 默认的构造函数如果没有在类中定义构造函数 则编译系统自动地生成一个默认的构造函数 例如 编译系统为类Date生成下述形式的构造函数 Date Date 或 例如 编译系统为类complex生成下述形式的构造函数 complex complex 这个默认的构造函数 不带任何参数 只能为对象开辟一个存储空间 而不能给对象中的数据成员赋初值 例3 13一个没有对数据成员赋初值的例子 includeusingnamespacestd classMyclass public intno intmain Myclassa cout a no endl return0 运行结果如下 858993460 不难看出 本例的运行结果是一个随机数 在实际使用时可能会造成错误 说明 1 对没有定义构造函数的类 其公有数据成员可以用初始值表进行初始化 请看以下例子 例3 14用初始值表初始化公有数据成员 includeusingnamespacestd classMyclass public charname 10 intno intmain Myclassa chen 25 cout a name a no endl return0 运行结果如下 chen25 用初始值表初始化公有数据成员 2 只要一个类定义了一个构造函数 不一定是无参构造函数 系统将不再给它提供默认的构造函数 includeclassLocation private intX Y public voidInit intinitX intinitY X initX Y initY intGetX returnX intGetY returnY intmain LocationA3 A3 Init 785 980 cout A3 GetX A3 GetY endl return0 类中没有用户定义的构造函数 C 编译系统自动地生成一个默认的构造函数 定义对象时 就调用这个自动生成的默认的构造函数 运行结果 785980 include 例3 15分析下列程序的运行结果 usingnamespacestd classDate public Date inty intm intd 带有参数的构造函数voidsetDate inty intm intd voidshowDate private intyear intmonth intday Date Date inty intm intd year y month m day d voidDate setDate inty intm intd year y month m day d inlinevoidDate showDate cout year month day endl intmain Datedate1 date1 setDate 2002 11 14 date1 showDate return0 程序的运行结果是 2002 11 14 错误的原因是 当类中定义了带有参数的构造函数后 系统将不再给它提供默认的构造函数 因此当定义类Date的对象date1时 找不到与之匹配的构造函数 include 例3 15分析下列程序的运行结果 usingnamespacestd classDate public Date inty intm intd 带有参数的构造函数voidsetDate inty intm intd voidshowDate private intyear intmonth intday Date Date inty intm intd year y month m day d voidDate setDate inty intm intd year y month m day d inlinevoidDate showDate cout year month day endl intmain Datedate1 date1 setDate 2002 11 14 date1 showDate return0 方法1 把语句 改为Datedate1 2002 11 14 解决方法 方法2 增加一个如下的构造函数Date 2 默认的析构函数每个类必须有一个析构函数 若没有显式地为一个类定义析构函数 编译系统会自动地生成一个缺省的析构函数 例如 Student student 当撤消对象时 这个缺省的析构函数将释放分配给对象的内存空间 对于大多数类而言 默认的析构函数就能满足要求 但是 如果在一个对象完成其操作之前需要做一些内部处理 则应该显式地定义析构函数 以完成所需的操作 例如 classString data public String data char str newchar max len String data delete str voidget info char voidsent info char private char str intmax len 3 4 6构造函数的重载C 允许构造函数重载 以适应不同的场合 这些构造函数之间以它们所带参数的个数或类型的不同而区分 例如 类A具有四个不同的构造函数 classA public A 不带参数的构造函数 A int 只带一个整型参数的构造函数 A int char 带两个参数的构造函数 A float char 带两个参数的构造函数 intmain Ax 调用构造函数A Ay 10 调用构造函数A int Az 10 z 调用构造函数A int char Aw 4 4 w 调用构造函数A float char 例3 17 1计时器 include includeclasstimer intseconds public timer 无参数构造函数 给seconds清0 seconds 0 timer char t 含一个数字串参数的构造函数 seconds atoi t timer intt 含一个整型参数的构造函数 seconds t timer intmin intsec 含两个整型参数的构造函数 seconds min 60 sec gettime returnseconds include includeclasstimer intseconds public timer seconds 0 timer char t seconds atoi t timer intt seconds t timer intmin intsec seconds min 60 sec intgettime returnseconds main timera b 10 c 20 d 1 10 cout seconds1 a gettime endl cout seconds2 b gettime endl cout seconds3 c gettime endl cout seconds4 d gettime endl return0 运行结果 seconds1 0seconds2 10seconds3 20seconds4 70 说明使用无参构造函数创建对象时 应该用语句 timera 而不能用语句 timera 因为语句 timera 表示声明一个名为timer的普通函数 此函数的返回值为timer类型 说明 在一个类中 当无参数的构造函数和带默认参数的构造函数重载时 有可能产生二义性 例如 classX public X 无参数的构造函数X inti 0 带默认参数的构造函数 intmain Xone 10 正确 调用带默认参数的构造函数Xtwo 它既可以调用无参数的构造函数 也可以调用带默认参数的构造函数 因此产生了二义性 3 4 7拷贝构造函数拷贝构造函数的其作用是 在建立一个新对象时 使用一个已经存在的对象去初始化这个新对象 例如 Pointp2 p1 其作用是 在建立新对象p2时 用已经存在的对象P1去初始化新对象p2 在这个过程中就要调用拷贝构造函数 拷贝构造函数有以下两种 用户自定义的拷贝构造函数 系统自动生成的默认的拷贝构造函数 1 自定义拷贝构造函数自定义拷贝构造函数的一般形式如下 类名 类名 const类名 对象名 拷贝构造函数的函数体 已经存在的对象 下面是一个用户自定义的拷贝构造函数 classpoint intx y public point inta intb 构造函数 x a y b point constpoint p 拷贝构造函数 x 2 p x y 2 p y main pointp1 10 20 p

温馨提示

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

评论

0/150

提交评论