C类和对象知识点复习.ppt

上传人:max****ui 文档编号:8614298 上传时间:2020-03-30 格式:PPT 页数:108 大小:987KB
返回 下载 相关 举报
C类和对象知识点复习.ppt_第1页
第1页 / 共108页
C类和对象知识点复习.ppt_第2页
第2页 / 共108页
C类和对象知识点复习.ppt_第3页
第3页 / 共108页
点击查看更多>>
资源描述
第3章类和对象3 1类的构成3 2成员函数的定义3 3对象的定义和使用3 4构造函数与析构函数3 5对象的赋值与复制3 6自引用指针this3 7C 的string类 3 1类的构成3 1 1从结构体到类3 1 2类的构成 3 1 1从结构体到类1 结构体的扩充例如下面声明了一个日期结构体 structDate intyear 年intmonth 月intday 日 C语言结构体一般格式如下 struct结构名 数据 例3 1有关日期结构体的例子 includeusingnamespacestd structDate 声明了一个名为Date的结构体intyear intmonth intday intmain Datedate1 date1 year 2014 可以在结构体外直接访问数据yeardate1 month 3 可以在结构体外直接访问数据monthdate1 day 1 可以在结构体外直接访问数据daycout date1 year date1 month date1 day endl return0 程序的运行结果如下 2014 3 1 C语言中的结构体缺点 结构体变量可以在结构体外直接访问数据 在C结构体中的数据是很不安全的 C 中引入了类的概念 克服了C结构体的缺点 C 中引入了类的概念 它不仅可以含有数据 而且还可以含有函数 类中的数据和函数 分别称作数据成员和成员函数 类声明的简化格式如下 class类名 数据函数 类的声明由关键字class打头 后跟类名 花括号中是类体 以一个分号 结束 类声明的简化格式如下 class类名 数据成员函数函数 3 1 2类的构成在类中 数据成员和成员函数分别属于private部分 和public部分 数据成员和成员函数一般也统称为类的成员 类声明的一般格式如下 class类名 public 公有数据成员 公有成员函数 private 私有数据成员 私有成员函数 公有成员既可被类内的成员函数访问 也可被类的外部访问 是类与外界的接口 私有成员只能被类内的成员函数访问 而类外部的任何访问都是非法的 用一个类Date来描述日期 其形式如下 classDate public voidsetDate inty intm intd 公有成员函数voidshowDate 公有成员函数private intyear 私有数据成员intmonth 私有数据成员intday 私有数据成员 私有数据成员year month和day只能由内部成员函数访问 在类的外部无法访问 保护了私有数据的安全 设置日期成员函数setDate和日期显示成员函数showDate都是公有的成员函数 类外部对类Date的数据进行操作 只能通过这两个函数来实现 说明 1 除了private和public之外 类中的成员还可以用另一个关键字protected来说明 被protected说明的数据成员和成员函数称为保护成员 类声明的完整格式如下 class类名 public 公有数据成员 公有成员函数 protected 保护数据成员 保护成员函数 private 私有数据成员 私有成员函数 保护成员可以由本类的成员函数访问 也可以由本类的派生类的成员函数访问 而类外的任何访问都是非法的 2 具体的类来 类声明格式中的3个部分并非一定要全有 但至少要有其中的一个部分 一般情况 一个类的数据成员应该声明为私有成员 成员函数声明为公有成员 内部的数据整个隐蔽在类中 在类的外部根本就无法看到 使数据得到有效的保护 3 类声明中的private protected和public三个关键字可以按任意顺序出现任意次 但是 如果把所有的私有成员 保护成员和公有成员归类放在一起 程序将更加清晰 4 C 规定 在默认情况下 即没有指定成员是私有 保护或公有时 类中的成员是私有的 例3 2将例3 1中的结构体struct改为类class includeusingnamespacestd classDate 将例3 1中的结构体struct改为类classintyear 私有数据成员intmonth 私有数据成员intday 私有数据成员 intmain Datedate1 date1 year 2014 错误 在类外不能访问私有数据成员yeardate1 month 3 错误 在类外不能访问私有数据成员monthdate1 day 1 错误 在类外不能访问私有数据成员daycout date1 year date1 month date1 day endl 错误 不能访问私有数据成员return0 私有成员只能被类内的成员函数访问 而类外部的任何访问都是非法的 如何才能访问类中的私有数据成员呢 include 例3 1有关日期结构体的例子 usingnamespacestd structDate 声明了一个名为Date的结构体intyear 公有的数据成员intmonth 公有的数据成员intday 公有的数据成员intmain Datedate1 date1 year 2014 可以在结构体外直接访问数据yeardate1 month 3 可以在结构体外直接访问数据monthdate1 day 1 可以在结构体外直接访问数据daycout date1 year date1 month date1 day endl return0 程序的运行结果如下 2014 3 1 在默认情况下 结构体中的成员是公有的 因此 例3 1中数据成员year month和day默认为是公有的 结构体外的变量date1能够对它们直接进行访问 5 不能在类声明中给数据成员赋初值 例如 classabc private chara q 错误intb 33 错误public C 规定 只有在对象定义之后才能给数据成员赋初值 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 floatscore1 在类外定义成员函数时 不但要说明参数表中参数的类型 还必须要指出其参数名 例如 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 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 学生类的完整程序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 1201 95 stu2 input 1202 75 stu1 print stu2 print stu1 modify 85 5 stu1 print stu2 print return0 stu1 number 1201 stu1 score 95stu2 number 1202 stu2 score 75 stu1 score 85 5 运行结果 number 1201score 95number 1202score 75number 1201score 85 5number 1202score 75 include 例3 3 1通过对象名和对象选择符访问对象中的成员 usingnamespacestd classDate public voidsetDate inty intm intd voidshowDate private intyear intmonth intday voidDate setDate inty intm intd year y month m day d voidDate showDate cout year month day endl intmain Datedate1 cout Date1setandoutput endl date1 setDate 2014 3 1 date1 showDate return0 调用对象date1的公有成员函数setDate 给date1的私有数据成员赋值 调用对象date1公有成员函数showDate 显示date1的私有数据成员 程序运行结果如下 Date1setandoutput 2014 3 1 说明 在类外只能访问公有 public 成员 而不能访问私有 private 成员 如果将例3中的主程序改成下面的形式 将出现编译错误 intmain Datedate1 date1 year 2014 date1 month 3 date1 day 1 cout date1 year date1 month date1 day endl return0 错误 在类的外部 对象date1不能访问私有数据成员year month和day 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 4构造函数与析构函数3 4 1对象的初始化和构造函数3 4 2用成员初始化表对数据成员初始化3 4 3析构函数3 4 4默认的构造函数和默认的析构函数3 4 5带默认参数的构造函数3 4 6构造函数的重载 3 4 1对象的初始化和构造函数与使用变量一样 对象时也应该 先定义 后使用 在定义对象时 对数据成员赋初值 称为对象的初始化 C 规定 类声明体中不能给数据成员直接赋初值 下面的写法是错误的 classDate private intyear 2014 错误intmonth 3 错误intday 1 错误 对象的初始化常采用以下两种方法 1 调用普通的成员函数来完成2 调用构造函数来完成 classDate public voidsetDate inty intm intd voidshowDate private intyear intmonth intday intmain Datedate1 date1 setDate 2014 3 1 return0 调用对象date1的公有成员函数setDate 给date1的私有数据成员赋初值 初始化后 Date1 year 2014Date1 month 3Date1 day 1 1 用普通成员函数对对象进行初始化 在建立对象的时 采用构造函数给数据成员赋初值 通常有以下两种形式 形式1 类名对象名 实参表 这里的 类名 与构造函数名相同 实参表 是为构造函数提供的实际参数 2 用构造函数对对象进行初始化 构造函数是一种特殊的成员函数 它主要用于 1 为对象分配空间 2 为对象的数据成员进行初始化 3 其他指定的任务 include 例3 5 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 2014 3 1 date1 showDate return0 3 定义类Date的对象date1 调用构造函数 给对象date1的数据成员赋初值 2 构造函数可以有任意类型的参数 但不能具有返回类型 1 构造函数的名字必须与类名相同 通常 利用构造函数建立对象有以下二种方法 1 一般形式为 类名对象名 实参表 例如 complexA 1 1 2 2 类名对象名实参表 在建立对象的时 采用构造函数对对象进行初始化 通常有以下两种形式 形式1 例如 Datedate1 2014 3 1 类名对象名实参表 建立对象时 编译系统会自动地调用构造函数 对对象进行初始化 类名对象名 实参表 形式2 其一般语法形式为 例如 Date pdate newDate 2014 3 1 类名 指针变量名 new类名 实参表 指针pdate指向该对象的地址对象名 匿名对象 或称对象名是 pdate 此时 应使用 来访问对象的成员 而不是 类名 指针变量名 new类名 实参表 将例3 5 1的主函数改成用这种方法来实现 intmain Date pdate newDate 2014 3 1 pdate showDate deletepdate return0 利用构造函数创建对象的另一种方法 用指针和new来实现 说明 1 构造函数的名字必须与类名相同 否则编译程序将把它当作一般的成员函数来处理 2 构造函数没有返回值 在声明和定义构造函数时 是不能说明它的类型的 甚至说明为void类型也不行 例如上述构造函数不能写成voidDate inty intm intd 说明为void类型也不行 3 与普通的成员函数一样 构造函数的函数体可写在类体内 也可写在类体外 如例3 5 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 2014 3 1 5 构造函数可以是不带参数的 例如 classA private intx public A x 50 intmain Aa 构造函数可以不带参数 定义类A的对象a时 调用不带参数的构造函数给数据成员x赋初值50 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 初始值1 数据成员名2 初始值2 include 例3 6usingnamespacestd classDate public Date inty intm intd 声明构造函数的原型voidshowDate private intyear intmonth intday Date Date inty intm intd year y month m day d voidDate showDate cout year month day endl intmain Datedate1 2014 3 1 定义类Date的对象date1date1 showDate return0 定义构造函数Date 使用成员初始化表对数据成员初始化 运行结果如下 2014 3 1 说明 数据成员是按照它们在类中声明的顺序进行初始化的 与它们在成员初始化列表中列出的顺序无关 练习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析构函数析构函数也是一种特殊的成员函数 它执行与构造函数相反的操作 通常用于执行一些清理任务 主要有 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 7含有构造函数和析构函数的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 2014 3 1 date1 showDatereturn0 程序运行结果如下 constructing 2014 3 1destruting 定义类Date的对象date1 调用date1的构造函数 初始化对象date1 说明 在以下情况 当对象的生命周期结束时 析构函数会被自动调用 如果定义了一个全局对象 则在程序流程离开其作用域时 如main函数结束或调用exit函数 时 调用该全局对象的析构函数 如果一个对象被定义在一个函数体内 则当这个函数结束时 该对象的析构函数被自动调用 若一个对象是使用new运算符动态创建的 在使用delete运算符释放它时 delete会自动调用析构函数 include 例3 8较完整的学生类示例 includeusingnamespacestd classStudent public Student char name1 char stu no1 floatscore1 声明构造函数 Student 声明析构函数voiddisp 成员函数 用于显示数据private char name char stu no floatscore 姓名 学号 成绩Student Student char name1 char stu no1 floatscore1 name newchar strlen name1 1 strcpy name name1 stu no newchar strlen stu no1 1 strcpy stu no stu no1 score score1 定义构造函数 Student Student 定义析构函数 delete name delete stu no voidStudent disp cout name name endl cout stu no stu no endl cout score score endl intmain Studentstu1 Liming 20130201 90 stu1 disp Studentstu2 Wangfun 20130202 85 stu2 disp return0 定义类Student的对象stu1 调用构造函数 初始化对象stu1 定义类Student的对象stu2 调用构造函数 初始化对象stu2 运行结果如下 name Limingstu no 20130201score 90name Wangfunstu no 20130202score 85 3 4 4默认的构造函数和默认的析构函数1 默认的构造函数如果没有在类中定义构造函数 则编译系统自动地生成一个默认的构造函数 例如 编译系统为类Date生成下述形式的构造函数 Date Date 这个默认的构造函数 不带任何参数 只能为对象开辟一个存储空间 而不能给对象中的数据成员赋初值 例3 9一个没有对数据成员赋初值的例子 includeusingnamespacestd classMyclass public intno intmain Myclassa cout a no endl return0 运行结果如下 858993460 不难看出 本例的运行结果是一个随机数 在实际使用时可能会造成错误 说明 1 对没有定义构造函数的类 其公有数据成员可以用初始值表进行初始化 请看以下例子 例3 10用初始值表初始化公有数据成员 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 10分析下列程序的运行结果 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 2013 11 14 date1 showDate return0 程序的运行结果是 2013 11 14 错误的原因是 当类中定义了带有参数的构造函数后 系统将不再给它提供默认的构造函数 因此当定义类Date的对象date1时 找不到与之匹配的构造函数 include 例3 10分析下列程序的运行结果 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 2013 11 14 date1 showDate return0 方法1 把语句 改为Datedate1 2013 11 14 解决方法 方法2 增加一个如下的构造函数Date 2 默认的析构函数每个类必须有一个析构函数 若没有显式地为一个类定义析构函数 编译系统会自动地生成一个缺省的析构函数 例如 Date Date 当撤消对象时 这个缺省的析构函数将释放分配给对象的内存空间 说明 对于大多数类而言 默认的析构函数就能满足要求 但是 如果在一个对象完成其操作之前需要做一些内部处理 则应该显式地定义析构函数 以完成所需的操作 如例3 8中的析构函数 Student Student delete name 释放由运算符new分配的内存空间delete stu no 释放由运算符new分配的内存空间 3 4 5带默认参数的构造函数在实际使用中 有些构造函数的参数值在大部分情况是相同的 只有在特殊情况下才需要改变它的参数值 例如大学本科的学制一般默认为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 说明 在一个类中定义了全部是默认参数的构造函数后 不能同时再声明无参数的默认构造函数 或其他重载构造函数 例如在一个类中有以下构造函数的声明 Box inth 10 intw 10 intlen 10 就不能再声明无参数的构造函数 Box 否则 如用下面的语句建立对象Boxbox1 编译系统将无法判断应该调用哪个构造函数 因此产生了二义性 声明全部是默认参数的构造函数 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 include 例3 13构造函数重载的示例 usingnamespacestd classRectangle public Rectangle 声明无参数的构造函数Rectangle intlen intwid 声明带有参数的构造函数intarea return length width private intlength width Rectangle Rectangle length 10 width 10 定义无参数的构造函数Rectangle Rectangle intlen intwid 定义带有参数的构造函数 length len width wid intmain Rectanglerec1 定义对象rec1 调用无参数的构造函数cout Theareaofrectangle1is rec1 area endl Rectanglerec2 15 20 定义对象rec2 调用带有参数的构造函数cout Theareaofrectangle2is rec2 area endl return0 程序运行结果如下 Theareaofrectangle1is100Theareaofrectangle2is300 说明 1 使用无参构造函数创建对象时 应该用语句 Rectanglerec1 而不能用语句Rectanglerec1 因为语句 Rectanglerec1 表示声明一个名为rec1的普通函数 此函数的返回值为Rectangle类型 2 在一个类中 当无参数的构造函数和带默认参数的构造函数重载时 有可能产生二义性 例如 classX public X 无参数的构造函数X inti 0 带默认参数的构造函数 intmain Xone 10 正确 调用带默认参数的构造函数Xtwo 它既可以调用无参数的构造函数 也可以调用带默认参数的构造函数 因此产生了二义性 3 5对象的赋值与复制3 5 1对象赋值语句3 5 2拷贝构造函数 3 5 1对象赋值语句变量之间可以进行赋值 intA B B A 同类型的对象之间也可以进行赋值 对象赋值的一般形式为 当一个对象赋值给另一个对象时 所有的数据成员都会逐位拷贝 对象名1 对象名2 include 例3 14 1usingnamespacestd 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 运行结果 341234 说明 1 在使用对象赋值语句进行对象赋值时 两个对象的类型必须相同 如对象的类型不同 编译时将出错 2 两个对象之间的赋值 仅仅是对其中的数据成员赋值 而不对成员函数赋值 数据成员是占存储空间的 不同对象的数据成员占有不同的存储空间 而不同对象的成员函数是占有同一个函数代码段 无法对它们赋值 3 5 2拷贝构造函数拷贝构造函数的其作用是 在建立一个新对象时 使用一个已经存在的对象去初始化这个新对象 例如 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 pointp2 p1 return0 自定义的拷贝构造函数 下面是一个用户自定义的拷贝构造函数 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 pointp2 p1 return0 相当于 constpoint p p1 类似执行以下语句 pointp2 p2 x 2 p1 x p2 y 2 p1 y 下面是一个用户自定义的拷贝构造函数 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 pointp2 p1 return0 相当于 constpoint p p1 结果为 p1 x 10 p1 y 20p2 x 20 p2 y 40 include 例3 15 1classpoint intx y public point inta intb x a y b 构造函数point constpoint 定义对象p1 调用了普通的构造函数 调用拷贝构造函数 用对象p1初始化对象p2 程序运行结果如下 30406080 拷贝构造函数的特点 point constpoint p 自定义的拷贝构造函数 x 2 p x y 2 p y 该函数与类同名 并且不能指定返回值类型 因为它也是一种构造函数 该函数只有一个参数 并且是同类对象的引用 每个类必须有一个拷贝构造函数 调用拷贝构造函数的两种方法 代入 法调用 赋值 法调用例如 main pointp1 10 20 pointp2 p1 pointp3 p1 代入 法调用拷贝构造函数 赋值 法调用拷贝构造函数 类名对象2 对象1 类名对象2 对象1 2 默认的拷贝构造函数如果没有编写自定义的拷贝构造函数 C 系统会自动地生成的一个默认的拷贝构造函数 在建立一个新对象时 这种默认的拷贝构造函数能够将一个已存在的对象的数据成员一比一地复制给新对象 例如 p1 p2为类point的两个对象 且对象p1已经存在 则下述语句可以调用默认的拷贝构造函数建立并初始化对象p2 classpoint intx y public point inta intb x a y b pointp1 10 20 定义类point的对象p1pointp2 p1 构造函数 p1 x 10 p1 y 20 C 系统会自动地生成的一个默认的拷贝构造函数 将一个已存在的对象的数据成员一比一地复制给新对象 将对象p1作为参数 调用默认的拷贝构造函数初始化p2 例如 p1 p2为类point的两个对象 且对象p1已经存在 则下述语句可以调用默认的拷贝构造函数建立并初始化对象p2 classpoint intx y public point inta intb x a y b pointp1 10 20 定义类point的对象p1pointp2 p1 构造函数 将对象p1作为参数 调用默认的拷贝构造函数初始化p2 类似执行以下语句 pointp2 p2 p1 结果为 p1 x 10 p1 y 20p2 x 10 p2 y 20 3 调用拷贝构造函数的3种情况 1 当用类的一个对象去初始化该类的另一个对象时 拷贝构造函数将会被调用 例如 Pointp2 p1 用 代入 法调用拷贝构造函数 用对象p1初始化对象p2Pointp3 p1 用 赋值 法调用拷贝构造函数 用对象p1初始化对象p3 2 当函数的形参是类的对象 在调用函数进行形参和实参结合时 拷贝构造函数将会被调用 例如 voidfun1 Pointp 形参是类Point的对象p p print intmain Pointp1 10 20 fun1 p1 调用函数fun1时 实参p1是类Point的对象 将调用拷贝构造函数 初始化形参对象preturn0 3 当函数的返回值是类的对象 在函数调用完毕将返回值 对象 带回函数调用处时 此时就会调用拷贝构造函数 将此对象复制给一个临时对象并传到该函数的调用处 例如 Pointfun2 函数fun2的返回值类型是Point类类型 Pointp1 10 30 定义类Point的对象p1returnp1 函数的返回值是Point类的对象 intmain Pointp2 定义类Point的对象p2P2 fun2 函数执行完成 返回调用者时 调用拷贝构造函数return0 例3 17 1 includeusingnamespacestd classPoint public Point inta intb 定义构造函数 x a y b cout Usingnormalconstructor n Point constPoint 第1次调用拷贝构造函数 运行结果 UsingnormalconstructorUsingcopyconstructor6080 例3 17 2 includeclassPoint public Point inta intb 定义构造函数 x a y b cout Usingnormalconstructor n Point constPoint 调用函数fun2结束时 第2次调用拷贝构造函数 运行结果 UsingnormalconstructorUsingcopyconstructorUsingnormalconstructorUsingcopyconstructor 3 6自引用指针this成员函数的存储方式classBox intx intprint cout x Box对象1 对象2 对象3 不同对象的数据成员存放在不同的内存地址 所有对象的成员函数对应的是同一个函数
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!