C C++程序设计教程.pptx_第1页
C C++程序设计教程.pptx_第2页
C C++程序设计教程.pptx_第3页
C C++程序设计教程.pptx_第4页
C C++程序设计教程.pptx_第5页
已阅读5页,还剩100页未读 继续免费阅读

下载本文档

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

文档简介

1、C/C+程序设计教程,2020/8/19,2,第1章 类和对象,应该重点掌握以下内容: 面向对象程序设计的基本特点 类和对象的定义和使用 构造函数和析构函数 拷贝构造函数和堆对象、对象数组 友元函数和友元类,2020/8/19,3,第1章 类和对象,1.1 面向对象程序设计概述 1.2 面向对象程序设计的基本概念 1.3 类和对象的定义 1.4 构造函数和析构函数 1.5 类和对象的进一步应用 1.6 静态成员 1.7 友元函数和友元类 1.8 string类 1.9 综合应用实例,2020/8/19,4,1.1 面向对象程序设计概述,一、什么是面向对象程序设计 面向对象程序设计(Object

2、 Oriented Programming-简称OOP)是软件系统设计与实现的新方法,这种新方法即吸取了结构化程序设计的全部优点,又考虑了现实世界与面向对象空间的映射关系,所追求的目标是将现实世界的问题求解尽可能的简单化。 二、面向对象程序设计的基本思路 例如:生产一台电脑,2020/8/19,5,1.2 面向对象程序设计的基本概念,1.2.1 类 1.2.2 对象 1.2.3 封装(encapsulation)与数据隐藏 1.2.4 继承(inheritance) 1.2.5 多态性(polymorphism) 1.2.6 消息,2020/8/19,6,1.2.1 类,一、现实世界与面向对象

3、系统对应关系 二、什么是类 1. 类是一种复杂的数据类型,它将不同类型的数据和与这些数据相关的操作封装在一起。类是对现实世界客观事物的抽象。 2. 两方面的要素: 属性(atrribute)-数据 行为(behavior) -数据的操作 (函数),2020/8/19,7,1.2.2 对象,一、什么是对象 对象是类的一个实体,又称为实例 二、对象与类的关系 三、对象与对象之间消息传递,2020/8/19,8,1.2.3 封装与数据隐藏,一、什么是封装 封装是指将对象的数据和与这个数据有关的操作放在一起。 各个对象之间相互独立,互不干扰。 对象只留少量的接口,以便与外部联系。从外部看对象就像一个“

4、黑匣子”,数据和方法是隐蔽的、看不见的。 当用户使用对象时,不必知道对象的具体实现细节,只需要根据对象提供的外部接口访问对象即可。 二、封装应具有以下几个特点 具有一个清楚的边界,私有成员封装在内部,外部不可以访问 提供必要的接口 对象内部的数据和方法是受封装外壳保护的,其它对象不能直接使用。,2020/8/19,9,1.2.4 继承,一、继承概念的提出 例如:已定义电视机类,现需要定义彩色电视机类 解决方法: 1.重新设计 2.继承:继承原来电视机的属性和方法,再添加彩色电视机自己特有的新的属性和行为 二、继承的概念 C+提供的继承机制提供了类之间相互关系的解决方案,使某个类可以继承另外一个

5、类的特征和能力。 使用继承符合人们对事物的认识和叙述,大大简化了对问题的描述,提高了程序的可重用性,从而提高了程序设计、修改、扩充的效率,实现软件重用(software reusability)。,2020/8/19,10,1.2.5 多态性(polymorphism),一、多态性的概念 多态性:描述的是同一个消息可以根据发送消息对象的不同采用不同的行为方式。 例如: 学校的上课铃响,不同班级的学生进入不同的教室学习,不同的老师进入不同教室开始讲课,不同的对象会作出不同的响应。可以看到学生和教师在接受到同一消息(上课铃声)时,执行不同的操作,这就是多态的表现。 二、C+支持多态 静态多态性 动

6、态多态性,2020/8/19,11,1.2.6 消息,面向对象技术的封装使得对象相互独立,各个对象要相互协作实现系统的功能则需要对象之间的消息传递机制。消息是一个对象向另一个对象发出的服务请求,进行对象之间的通信。也可以说是一个对象调用另一个对象的方法(Method)或称为函数(Function)。,2020/8/19,12,面向过程与面向对象程序设计方法的比较,一、面向过程程序设计方法 程序 = 数据结构+算法 二、面向对象程序设计方法的规律是: 对象 = (数据结构+ 算法) 程序 = 对象 + 对象 + 对象 + + 对象,2020/8/19,13,1.3 类和对象的定义,一、类定义组成

7、 数据成员:说明类的属性 成员函数(又称函数成员):对类数据成员操作的类内函数,又称为方法。 二、类定义的一般格式为 class 类名 public : 数据成员和成员函数实现 protected: 数据成员和成员函数实现 private: 数据成员和成员函数实现 ;,2020/8/19,14,1.3.1 类的定义,说明: (1)定义一个类时,使用关键字class;类名必须是一个合法的变量名,C+中习惯用C或T开头,例如CStudent; (2)一个类包括类头和类体两部分。class ,称为类头(class head); (3)大括号中定义的是类的数据成员和成员函数,称为类体(class bo

8、dy)。类定义结束要用“;”结束; (4)关键字public(公有)、 protected(保护) 和private(私有)称为成员访问限定符(mumber access specifier)。用访问限定符声明了各个数据成员和成员函数的访问权限。,2020/8/19,15,1.3.1 类的定义,三、访问限定符 公有(public):提供了与外界的接口功能。公有成员可以被本类中的成员使用和访问,还可以被类作用域内的其他外在其他函数使用。 私有(private):封装在类内部的,只能被该类的成员和该类友元函数或友元类访问,任何类以外的函数对私有成员的访问都是非法的。 保护(protected:访问

9、权限介于私有和公有中间,类的成员可以访问,类以外的其他函数不能访问保护成员。 不同访问权限关系图,2020/8/19,16,1.3.1 类的定义,例:定义一个日期类Cdate,2020/8/19,17,#include class Cdate /使用关键字class声明一个类,类名为Cdate public: /以下是公有成员函数 void Setdate (int y, int m,int d)/设置日期 year=y; month=m; day=d; /以上3行是函数的实现 int Isleapyear()/判断日期是不是闰年 return (year%4=0,2020/8/19,18,1

10、.3.2 成员函数的定义,类的成员函数也是函数的一种,它的与以前介绍的普通函数用法基本一样。 成员函数由函数头和函数体组成,函数头包括函数名、函数的参数及函数的类型。函数体主要说明函数实现的功能。 成员函数与一般函数的区别在于:它属于类的成员,出现在类体中,是类的一部分。使用类的成员函数时,要考虑类成员函数的访问权限。 类的成员函数可以在类体中定义,也可以在类体中声明类成员函数,成员函数的实现在类外定义。,2020/8/19,19,1 在类内定义成员函数,#include class Cdate public: void Setdate (int y, int m,int d) /在类内定义成

11、员函数 year=y; month=m; day=d; int Isleapyear()return (year%4=0 说明:在类内定义的成员函数默认的是内联函数(inline函数)。一般把规模比较小的成员函数在类内定义。,2020/8/19,20,2 在类外定义成员函数,通常情况下 C+程序员习惯在类体中只定义数据成员以及成员函数的声明,而将成员函数的实现写在类外。因此类的定义由两部分组成: 声明部分 声明类的数据成员类型和成员函数的参数类型、个数以及返回值类型。 实现部分 对说明类成员函数的具体实现,2020/8/19,21,2 在类外定义成员函数,一、定义的格式 /类声明部分 clas

12、s 类名 public: private: Protected: 数据成员类型 数据成员名; 数据成员类型 数据成员名; 函数类型 成员函数名(参数表); 函数类型 成员函数名(参数表); ; /类实现部分 函数类型 类名 :成员函数名(参数表) /实现 ,2020/8/19,22,2 在类外定义成员函数,说明: (1)在类声明部分,包括数据成员的定义和成员函数的声明。 (2)成员函数的声明主要说明函数的类型,函数的参数个数及类型,并用“;”结束。 (3)函数实现部分是对在类中定义的成员函数完成功能的实现,包括函数头和函数体。在类体中直接定义函数时,不需要在函数名前面加上类名,因为函数属于哪一

13、个类是不言而喻的。但成员函数在类外定义时,必须在函数名前面加上类名,给与限定(qualifed),“”是作用域限定符(field qualifier)或称作用域运算符,用它声明函数是属于哪个类的。如果在作用域运算符“”的前面没有类名,或者函数名前面既无类名又无作用域运算符“”,则表示display函数不属于任何类,该函数不是成员函数,而是全局函数,即非成员函数的一般普通函数。,2020/8/19,23,2 在类外定义成员函数,例:Cdate类定义 / Cdate类声明部分 class Cdate public: /函数声明 void Setdate (int y, int m,int d);

14、/或void Setdate (int, int,int); int Isleapyear(); void Print(); private: int year,month ,day; date1,date2,date3; / Cdate类成员函数的实现 void Cdate: Setdate (int y, int m,int d) year=y; month=m; day=d; ,int Cdate:Isleapyear() return (year%4=0 ,2020/8/19,24,1.3.3 类对象的定义,1先声明类类型,然后定义类对象 class 类名 数据成员和成员函数实现 ;

15、class 类名 对象列表 说明: (1)class 可选,可以写,也可以省略 (2)类名是定义好的类。 (3)对象列表的格式为:对象名,对象名,对象名。定义多个对象时,各对象名中间用逗号隔开。 如: class Cdate date1,date2,date3; /Cdate是已经声明的类类型 Cdate date1,date2,date3; /建议使用的方法。,2020/8/19,25,2在声明类类型的同时定义对象 class 类名 数据成员和成员函数实现 对象列表; 例: #include class Cdate /使用关键字class声明一个类,类名为Cdate public: /以下是

16、公有成员函数 void Setdate (int y, int m,int d)/设置日期 year=y; month=m; day=d; /以上3行是函数的实现 int Isleapyear()/判断日期是不是闰年 return (year%4=0 /声明类类型的同时定义了3个对象,1.3.3 类对象的定义,2020/8/19,26,1.3.3 类对象的定义,3不写类名,直接定义类对象 class 数据成员和成员函数实现 对象列表; 例如: class /没有类名 ,无类名 public: private: date1,date2,date3; /声明类类型的同时定义了3个对象 注意:C+中

17、不提倡使用,因为只能定义这一次对象,以后要想在定义这种类类型的对象,就需要把整个类定义再写一遍。,2020/8/19,27,1.3.4 对象成员的访问,(1)通过对象名和成员运算符访问对象中的成员的一般形式 对象名. 数据成员名 / “.”是成员运算符 对象名. 成员函数名 例如: Cdate d1; /定义一个Cdate类的对象d1 d1.Print(); /通过对象名和成员运算符访问对象中的公有成员 (2)通过指向对象的指针和指针运算符访问对象中的成员的一般形式 对象指针名 - 数据成员名 / “-”是指向运算符 对象指针名 - 成员函数名 例如: Cdate d,*p; /定义对象d和对

18、象指针变量p p=/通过指向对象的指针和指向运算符访问对象中的成员,2020/8/19,28,1.3.4 对象成员的访问,(3)通过对象的引用变量访问对象中的成员 如果为一个对象定义了一个引用变量,它们是共占同一段存储单元的,实际上它们是同一个对象,只是用不同的名字表示而已。因此完全可以通过引用变量来访问该对象中的成员。通过对象的引用变量访问该对象中的成员的格式与通过对象名访问对象中的成员的形式一样。 例如: Cdate d1; /定义对象d1 Cdate /引用变量访问对象中的成员,输出日期,2020/8/19,29,/ Cdate.h 在头文件中声明日期类 class Cdate publ

19、ic: void Setdate (int y, int m,int d); int Isleapyear(); void Print(); private: int year,month ,day; ; /Cdate.cpp 在与类定义头文件同名的cpp文件中定义成员函数实现部分 #include #include Cdate.h /包含类定义的头文件,否则出错 void Cdate: Setdate (int y, int m,int d) year=y; month=m; day=d; int Cdate:Isleapyear() return (year%4=0 ,void Cdate

20、:Print() cout Setdate(2000,4,2); /通过指针访问成员 d4. Setdate(2006,12,1); /通过引用访问成员 d1.Print(); p- Print(); d4.Print(); ,【例1.1】一个完整的Cdate类的应用程序。,程序运行结果: 1999-12-30 2000-4-2 2006-12-1,2020/8/19,30,例1.1程序执行过程,2020/8/19,31,【例1.2】封装一个学生类,学生的信息包括学生的姓名、学号、性别、年龄和3门的成绩。可以设置学生的各类信息,统计该学生的平均成绩并输出学生信息。,Cstudent的类图,20

21、20/8/19,32,/CStudent.h 这是头文件,在此文件中进行类的声明 class CStudent /类声明 public: void setinfo(char *,int ,char,int); void setgrad(float , float , float); float avg(); void display(); private: char name20; int id ; char sex; int age; float grad3; ; /CStudent.cpp在此文件中进行函数的定义 #include #include #include CStudent.h/

22、漏写此行编译通不过 void CStudent:setinfo(char *na,int i ,char s ,int a) strcpy(name,na); id=i; sex=s; age=a; void CStudent:setgrad(float a, float b, float c) grad0=a;,grad1=b; grad2=c; float CStudent:avg() return (grad0+ grad1 +grad2)/3; void CStudent:display( ) cout #include CStudent.h/将类声明头文件包含进来 int main(

23、 ) CStudent stud1;/定义对象 stud1. setinfo(张三,2006102,m,18); stud1.setgrad(79,98,87); stud1.display(); cout 平均成绩:stud1.avg(); return 0; ,运行结果: id:2006102 name:张三 sex:m age:18 平均成绩:88,2020/8/19,33,1.3.5 类对象的内存分配,C+中用同一内存空间来存放这个同种类对象的成员函数代码,当去调用某个对象的成员函数时,都去调用这个公用的函数代码。C+中用this指针来区分是哪个对象的成员函数。,2020/8/19,3

24、4,1.3.6 this指针,一、问题的提出 每个对象中的数据成员都分别占有存储空间,而成员函数都是同一代码段。如果对同一个类定义了n个对象,那么,当不同对象的成员函数引用数据成员时,怎么能保证引用的数据成员是属于哪个对象呢? 二、this指针 C+除了接受原有的参数外,还隐含的接受了一个特殊的指针参数,这个指针称为this指针。 它是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址,既this指针指向当前对象。,2020/8/19,35,【例1.13】设计矩形类CRect,说明this指针的用法。分析:矩形类数据成员包括左上角坐标(left和top)和矩形的长(lengt

25、h)和宽(width),定义成员函数set()设置矩形,成员函数area()计算矩形的面积。 #include class CRect public: CRect( ); void set( double t, double, double len, double wid); double area(); private: double left; double top; double length; double width; ; CRect:CRect() top = 0; /相当与this-top=0 left = 0; length = 0; width = 0; ,2020/8/19

26、,36,void CRect:set(double t, double lef, double len, double wid ) top = t; left = lef; length = len; width = wid; double CRect:area() return length* width; void main() CRect r1,r2; r1.set ( 10,10,10,10); r2.set ( 200,200,15,25); cout第一矩形的面积是:r1.area()endl; cout第二矩形的面积是:r2.area()endl; ,程序运行结果: 第一矩形的面

27、积是:100 第二矩形的面积是:375,void CRect:set(double t, double lef, double len, double wid ) top = t;/等价与this-top=t; left = lef;/等价与this- left = lef; length = len;/等价与this- length = len; width = wid;/等价与this- width = wid; ,2020/8/19,37,1.5 类和对象的进一步引用,在程序中经常需要访问对象中的成员,访问对象中的成员可以有3种方法: 通过对象名和成员运算符访问对象中的成员; 通过指向对

28、象的指针和指针运算符访问对象中的成员; 通过对象的引用变量访问对象中的成员。,2020/8/19,38,1.4 构造函数和析构函数,构造函数和析构函数的作用 1. 构造(constructor)函数 在创建对象时,系统自动调用它来初始化数据成员; 2. 析构(destructor)函数 在对象生存期结束的时候,自动调用来释放该对象。,2020/8/19,39,1.4.1 构造函数的定义,一、构造函数的定义格式: class 类名 public: 构造函数函数名(参数表); ;,2020/8/19,40,1.4.1 构造函数的定义,二、构造函数的特点 (1)构造函数是类的一个特殊的成员函数,函数

29、名与类名相同; (2)构造函数的访问属性应该是公有(public)访问属性; (3)构造函数的功能是对对象进行初始化,因此在构造函数中只能对数据成员做初始化,这些数据成员一般为私有成员,在构造函数中一般不做初始化以外的事情; (4)构造函数可以在类内定义也可以在类外定义; (5)构造函数无函数返回类型。注意:是什么也不写,也不可写void; (6)在程序运行时,当新的对象被建立,该对象所属的类的构造函数自动被调用,在该对象生存期中也只调用这一次。 (7)构造函数可以重载。类中可以有多个构造函数,它们由不同的参数表区分,系统在自动调用时按一般函数重载的规则选一个执行。,2020/8/19,41,

30、【例1.3】定义Cdate一个不带参数的构造函数。,#include class Cdate/定义一个日期类 public:/公有数据成员 Cdate()/定义构造函数 year=2000;/初始化数据成员 month=1; day=1; void Print()/一般成员函数 coutyear- month -dayendl; private: int year,month ,day; ; int main() Cdate d1; /自动调用构造函数,初始化数据成员 d1.Print(); return 0; ,程序运行结果为: 2000-1-1,2020/8/19,42,【例1.4】Cda

31、te类带参数的构造函数,#include class Cdate public: Cdate(int y, int m,int d); void Print(); private: int year,month ,day; ; Cdate:Cdate(int y, int m,int d) year=y; month=m; day=d; ,void Cdate:Print() coutyear- month -dayendl; int main() Cdate d1(1999,12,30),d2(2001,4,1); d1.Print(); d2.Print(); return 0; ,程序运

32、行结果: 1999-12-30 2001-4-1,2020/8/19,43,三、使用初始化表来实现对数据成员的初始化,初始化表的一般格式: 类名:构造函数名(参数列表):初始化表 构造函数其他实现代码 初始化表的格式: 对象成员1(参数名或常量),对象成员2(参数名或常量),对象成 员n(参数名或常量) 例如例1.4定义的构造函数可以改用以下形式: Cdate: Cdate(int y, int m,int d): year(y), month(m),day(d) 注意:这种写法方便、简洁。许多C+程序员喜欢用这种方式初始化所有的数据成员。除了构造函数可以使用初始化表外,类的其他成员函数也可以

33、根据需要使用初始化表。,2020/8/19,44,1.4.2 构造函数的重载,程序中需要以不同的方式初始化类对象时,可以在一个类中定义多个构造函数。即可以重载构造函数。C+定义对象时,根据声明中的参数个数和类型选择相应的构造函数初始化对象。,2020/8/19,45,【例1.5】Cdate类中的重载构造函数,#include class Cdate public: Cdate();/不带参数的构造函数,又称默认构造函数 Cdate(int y);/带1个参数的构造函数 Cdate(int y, int m); /带2个参数的构造函数 Cdate(int y, int m,int d); /带3

34、个参数的构造函数 void Print(); private: int year,month ,day; ; Cdate: Cdate()/构造函数的定义 year=2000; month=1; day=1; Cdate: Cdate(int y) year=y; month=1; day=1; ,Cdate: Cdate(int y, int m) year=y; month=m; day=1; Cdate: Cdate(int y, int m,int d) year=y; month=m; day=d; void Cdate:Print() coutyear- month -dayend

35、l; int main() Cdate day1; Cdate day2(2004); Cdate day3(2005,2); Cdate day4(2006,12,16); day1.Print(); day2.Print(); day3.Print(); day4.Print(); return 0; ,程序运行结果: 2000-1-1 2004-1-1 2005-2-1 2006-12-16,2020/8/19,46,1.4.2 构造函数的重载,关于构造函数C+规定: (1)每个类必须有一个构造函数,如果没有就不能创建任何对象; (2)若没有定义任何一个构造函数,C+提供一个默认的构造函

36、数,该构造函数没有参数,不做任何工作,相当一个空函数,例如: Cdate:Cdate() 所以在讲构造函数以前也可以定义一个对象,就是因为系统提供的默认构造函数。 (3)只要C+提供一个构造函数(不一定是没有参数的),C+不再提供默认的构造函数。也就是说为类定义了一个带参数的构造函数,还想要创建无参的对象时,则需要自己定义一个默认构造函数,2020/8/19,47,1.4.3 默认参数的构造函数,为什么使用默认参数的构造函数:对象常有一些初始值。 【例1.6】设计CPoint类,它带有默认参数的构造函数。 分析:一个点包括横坐标(x)和纵坐标(y)两个数据成员, 默认初始值为(0,0)。也可以

37、根据用户需要,初始化点为其他坐标,因此需要定义一个带默认参数的构造函数。定义成员函数print()输出该点。,CPoint类图,2020/8/19,48,#include class CPoint public: CPoint (double x1=0,double y1=0)/带默认参数的构造函数 x=x1; y=y1; void print () cout(x,y)endl; private: double x,y; ; main() CPoint point1; /自动调用带默认参数的构造函数,(0,0) CPoint point2(10);/自动调用带默认参数的构造函数,(10,0)

38、CPoint point3(20,30);/自动调用带默认参数的构造函数,(20,30) point1.print(); point2.print(); point3.print(); 注意:构造函数是对象创建时自动调用的,不能显式调用。,程序运行结果: (0,0) (10,0) (20,30),2020/8/19,49,一个类可以包括多个构造函数,但对每一个对象来说,对象创建时只能执行其中一个与对象参数相匹配的构造函数。下面代码存在二义性问题:,#include class CPoint public: /带默认参数的构造函数 CPoint (double x1=0,double y1=0)

39、 x=x1; y=y1; /带一个参数的构造函数 CPoint (double x1) x=x1; y=100; ,/其他成员函数 private: double x,y; ; main() CPoint point1(10); /错误,匹配哪个构造函数不确定 point1.print(); ,2020/8/19,50,1.4.4 析构函数,一、析构函数的作用 是一个特殊类成员函数,它的作用与构造函数相反。析构函数的作用 是在对象生存期结束之前自动执行,做清理工作。 例如: 一个类可能在构造函数中分配资源,这些资源要在对象的生存期结束 以前释放,释放资源的工作就是自动调用类的析构函数完成的。

40、二、析构函数的特点 (1)析构函数函数的名字特别,是类名加“”字符,表明它与构造函数相反; (2)析构函数没有参数,不能指定返回值类型; (3)一个类中只能定义一个析构函数,所以析构函数不能重载; (4)在对象生存期结束时,系统自动调用析构函数。,2020/8/19,51,1.4.4 析构函数,三、析构函数的定义格式 类名: 析构函数名() /实现代码 例如:Cdate:Cdate() ,2020/8/19,52,【例1.7】 设计一个简单的字符串类CString,类中有两个数据成员,分别表示字符串的长度和字符串的内容。定义一个构造函数和一个析构函数,成员函数GetLength( )返回字符串

41、长度,成员函数GetContents( )获得字符串的内容,重载成员函数SetContents( )可以改变字符串的值。 字符串类类图,2020/8/19,53,#include #include class CString public: CString(); /默认构造函数 CString(char *s);/带参数的构造函数 CString(); /析构函数 int GetLength();/得到字符串的长度 void GetContents(char *str);/得到字符串的内容 void SetContents(int len, char *cont);/重新设置字符串 void

42、SetContents(char *cont); /重载成员SetContents(),重新设置字符串 private: int length; /字符串长度 char *contents;/字符串内容 ; CString:CString() length = 0; contents = NULL; cout 字符串对象初始化:默认构造函数 endl; ,2020/8/19,54,CString:CString(char *s) length = strlen(s); contents = new charlength+1; strcpy(contents,s); cout 字符串对象初始化:

43、一个参数的构造函数 endl; CString:CString() cout contents 被销毁 endl; if(contents != NULL) delete contents; int CString:GetLength() return length; void CString:GetContents(char *str) strcpy(str, contents); ,2020/8/19,55,void CString:SetContents(int len, char *cont) length = len; if(contents != NULL) delete cont

44、ents; contents = new charlen+1; strncpy(contents,cont,length); contents length=0; cout 两个参数的SetContents函数 endl; void CString:SetContents( char *cont) length = strlen(cont); if(contents != NULL) delete contents; contents = new charlength+1; strcpy(contents,cont); cout 一个参数的SetContents函数 endl; ,2020/8

45、/19,56,void main() CString str1,str2;/两次调用默认的构造函数 CString str3(第三个字符串);/调用带参数的构造函数 str1.SetContents(第一个字符串);/调用一个参数的SetContents函数 str2.SetContents(20, 第二个字符串两个参数);/调用两个参数的SetContents函数 int i = str1.GetLength(); char string100; str1.GetContents(string); cout i string endl; i = str2.GetLength(); str2.

46、GetContents(string); cout i string endl; i = str3.GetLength(); str3.GetContents(string); cout i string endl; ,字符串对象初始化:默认构造函数(执行str1的构造函数) 字符串对象初始化:默认构造函数(执行str2的构造函数) 字符串对象初始化:一个参数的构造函数(执行str3的构造函数) 一个参数的SetContents函数 两个参数的SetContents函数 12 第一个字符串 20 第二个字符串两个参数 12 第三个字符串 第三个字符串被销毁 (执行str3的析构函数) 第二个字

47、符串两个参数被销毁 执行str3的析构函数) 第一个字符串被销毁 (执行str3的析构函数),2020/8/19,57,1.4.4 析构函数,四、构造函数和析构函数的调用时间和调用顺序 构造函数在创建对象时自动调用,调用的顺序是按照对象定义的次序。析构函数的调用顺序正好与构造函数相反。也就是说对于同一存储类别的对象是先构造的对象后析构,后构造的对象先析构。,2020/8/19,58,1.4.5 拷贝构造函数和默认拷贝构造函数,一、拷贝构造函数的作用 用一个已知的对象来初始化另一个对象 二、拷贝构造函数定义格式 类名:拷贝构造函数名(类名 (3)当对象作为函数的返回值,创建一个临时对象时。,20

48、20/8/19,59,【例1.8】设计一个复数类,两个数据成员分别表示复数的实部(real)和虚部(imag),2个构造函数分别在不同的情况下初始化对象,函数Print()用于输出复数。,#include class CComplex public: CComplex(double, double); CComplex(CComplex ,2020/8/19,60,CComplex:CComplex (CComplex ,程序运行结果: 调用两个参数的构造函数 调用两个参数的构造函数 调用拷贝构造函数 a = (3,4) c = (3,4) 调用拷贝构造函数 n=(5.6,7.9) 调用两个参

49、数的构造函数 调用拷贝构造函数 (8.6,11.9),2020/8/19,61,调用拷贝构造函数各对象数据成员变化,2020/8/19,62,1.4.5 拷贝构造函数和默认拷贝构造函数,当用户自定义了拷贝构造函数,所用一个对象创建另一个对象时,系统自动调用了用户自定义拷贝构造函数。如果用户没有自己定义拷贝构造函数,那么编译系统会自动会提供一个默认的拷贝构造函数。 四、默认拷贝构造函数 默认的拷贝构造函数所做的工作是将一个对象的全部数据成员赋值另一个对象的数据成员。C+把这种只进行对象数据成员简单赋值,称之为“浅拷贝”。 问题:什么时候一定需要用户自己定义拷贝构造函数呢?,2020/8/19,6

50、3,【例1.9】 设计一个班级类CClass,两个数据成员name和num分别表示班级的名称和人数。函数Print()输出班级名称和班级人数。,#include #include class CClass public: CClass (char *cName=,int snum=0); CClass () cout析构班级:pnameendl; delete pname; void Print(); private: char * pname; int num; ;,CClass :CClass (char *cName,int snum) int length = strlen(cName

51、); pname = new charlength+1; if (pname!=0) /或pname!=NULL strcpy(pname,cName); num=snum; cout创建班级:pnameendl; void CClass : Print() coutpname班的人数为:numendl; void main() CClass c1(计算机061班,56); CClass c2 (c1); c1.Print(); c2.Print(); ,/运行该程序出现错误! “浅拷贝”引起的运行错误,2020/8/19,64,c1、c2内存分配情况(浅拷贝),2020/8/19,65,问题

52、解决 : CClass (CClass ,运行结果: 创建班级:计算机061班 创建班级的拷贝:计算机061班 计算机061班班的人数为:56 计算机061班班的人数为:56 析构班级:计算机061班 析构班级:计算机061班,2020/8/19,66,c1、c2内存分配情况(深拷贝),2020/8/19,67,1.5 类和对象的进一步应用,1.5.1 堆对象 1.5.2 对象数组 1.5.3 类对象作为成员 1.5.4 面向对象程序中的常量,2020/8/19,68,1.5.1 堆对象,用new和 delete运算符定义堆对象的格式 类名 *p p=new 类名; delete p; 例如:

53、(Cdate类定义见例8.5) void main() Cdate *dp1,*dp2; /定义两个对象指针 dp1=new Cdate; /分配堆内存,调用缺省的构造函数,初始化堆对象的数据成员 dp2=new Cdate(2006,12,1); /调用带3个参数的构造函数,初始化堆对象的数据成员 dp1- Print(); /通过指针引用对象成员,输出日期200-1-1 (*dp2).Print(); /通过指针指向的对象引用对象成员,输出日期2006-12-1 delete dp1;/调用dp1的析构函数 delete dp2;/调用dp2的析构函数 ,2020/8/19,69,1.5.

54、2 对象数组,对象数组中的每一个元素都是类的对象 一、声明一维对象数组的语法形式 类名 数组名常量表达式; 注意:在建立数组时,同样要调用构造函数初始化每个数组元素。 如: CStudent s3 = CStudent(张三,2006001,19); /初始化第1个数组元素 CStudent(李四,2006002,18); /初始化第2个数组元素 CStudent(王五,2006003,20; /初始化第3个数组元素 二、引用对象数组元素的公有成员: 数组名下标 . 成员名;,2020/8/19,70,【例1.10】 设计一个学生类,假设一个班有5个学生,计算这个班学生的平均年龄。 分析:可以

55、定义一个学生对象数组表示5个学生对象,为了计算学生的平均年龄,学生类中需要有一个得到学生年龄的成员函数GetAge()。,#include #include class CStudent public: CStudent(char *na,int i ,int a); int GetAge(); private: char name20; int id; int age; ; CStudent:CStudent(char *na,int i ,int a) strcpy(name, na); id=i; age = a; ,int CStudent:GetAge() return age; v

56、oid main() int sum=0; CStudent s5 = CStudent(张三,10001, 20), /对象数组初始化 CStudent(李四,10002, 22 ), CStudent(王五,10003, 24 ), CStudent(赵六,10004, 26 ), CStudent(孙六,10005, 28 ); for(int i=0; i5; i+) sum += si.GetAge(); /累加每个学生的年龄 cout sum/5 endl; ,运行结果为 24,2020/8/19,71,1.5.3 类对象作为成员,有类对象作为成员称为组合类 一、通过构造函数的初始

57、化表为内嵌对象初始化 格式为: 类名:构造函数(参数表):内嵌对象1(参数表1),内嵌对象2(参数表2), 构造函数体 二、组合类构造函数的执行顺序为: (1)按内嵌对象的声明顺序依次调用内嵌对象的构造函数 (2)然后执行组合类本身的构造函数。,2020/8/19,72,【例1.11】设计一个学生类。数据成员包括学生的姓名、学号、性别、出生日期。 分析:学生的姓名、性别可以用简单的数据类型表示,学生的学号和出生日期可以用类对象表示。定义三个类:学生类、日期类和学号类。学生类是一个组合类,类的数据成员包括其他类对象,因此学生类的构造函数中使用初始化表初始化类对象数据成员。,2020/8/19,73,#include #include /日期类声明 class Cdate public: Cdat

温馨提示

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

评论

0/150

提交评论