版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第1章 初识C+ 默认参数 函数重载 引用 命名空间 控制台输入输出 类型增强 字符串类 new/delete 强制类型转换1.1.1 C+发展史C+是由Bjarne Stroustrup(比雅尼斯特劳斯特鲁普)博士在贝尔实验室工作期间发明并实现的。最初C+被称为new C,后来为了体现它是一种带类的面向对象语言,将其改名为C with class。直到1982年,Bjarne Stroustrup博士将C with class命名为C+。1.1.1 C+发展史C+的发展大致可以分为三个阶段:第一阶段从C+语言出现到1995年,这一阶段C+语言基本上是传统类型上的面向对象语言,并且依靠接近C语
2、言的效率,在计算机中占据着相当大的比重。在这期间Bjarne Stroustrup博士完成了经典巨著The C+ Programming Language第一版;诞生了一个传世经典ARM;之后模板、异常、命名空间等相继被加入。1.1.1 C+发展史第二阶段从1995到2000年,这一阶段由于STL库和后来的Boost库等程序库的出现,泛型编程设计在C+中的比重越来越大。同时由于Java、C#等语言的出现和硬件的影响,C+受到了一定的冲击。第三阶段从2000年至今,以Loki、MPL等程序库为代表的产生式编程和模板元编程的出现,使C+迎来了发展史上的又一个高峰。这些新技术和原有技术的融合,使C+
3、成为当今主流程序设计语言中最复杂的语言。1.1.2 C+的特点1.保持与C兼容C+既保留了C语言的所有优点,又克服了C语言的缺点,其编译系统能检查出更多的语法错误,因此C+比C语言更安全。绝大多数C语言程序可以不经修改直接在C+环境中运行,用C语言编写的众多库函数可以用于C+程序中。C+设计成与C兼容,完成了从C到C+的平滑过渡。1.1.2 C+的特点2.支持面向对象编程C+引入了面向对象的概念,使得开发人机交互类型的应用程序更为简单、快捷。通过类的层级关系进行编程,实现功能可扩展和增强的接口。具有诸如JAVA、PHP、Python等面向对象编程语言的特性。1.1.2 C+的特点3.拥有丰富的
4、库利用C+中的标准模板库STL,如set、map、hash等容器,可以快速编写代码。除此之外,数不胜数的第三方库,如扩充C+标准库的Boost库、图形库QT、图像处理库OpenCV、机器学习库Tensorflow、线性代数库Eigen、游戏库OpenGL等,这些优秀的库为企业的项目开发提供了非常大的支持,是必不可少的部分。1.1.2 C+的特点4.支持嵌入式开发C+在嵌入式开发领域有重要的地位,智能设备在生活随处可见,如智能手表、机器人等,这些智能设备的底层驱动和上层应用开发离不开C+语言的支持。C+11标准中增加的新特性,如原子操作、常量表达式、线程同步机制等,能够更加紧密的和硬件结合。1.
5、1.2 C+的特点5.类型安全增强C+和C语言属于强类型语言,C语言中可以进行强制类型转换,相对自由灵活。在C中强制类型转换被认为是设计的不合理,为了兼容C语言提供了三种类型转换形式。1.1.2 C+的特点6.支持垃圾回收机制大多数面向对象编程语言具有垃圾回收机制,而C+语言不具备垃圾回收机制,意味着申请的内存资源在使用完成后要自己释放还给系统。C+11标准的新特性智能指针,实现了内存资源的自动管理,使指针更加灵活并避免了内存泄漏。1.2 第一个C+程序1 #include 2 using namespace std;3 int main()4 5cout hello C+ endl;6 re
6、turn 0;7 例1-1 hello.cpp1.2 第一个C+程序C+程序文件以.cpp为扩展名,头文件仍然以.h为扩展名。但是,C+标准程序库头文件,一般不以.h结尾。例如,包含数学函数的头文件时,一般使用“#include”,而不使用“#include”。1.2 第一个C+程序第1行代码:包含了输入输出头文件 iostream,它是C+标准库头文件。第2行代码:引用标准命名空间std。第37行代码:定义main()函数。第5行代码:在屏幕上输出“hello C+”。第6行代码:通过return返回0。1.3.1 命名空间命名空间是C+语言的新特性,它能够解决命名冲突问题。例如,小明定义了
7、一个函数swap(),C+标准程序库中也存在一个swap()函数。此时,为了区分调用的是哪个swap()函数,可以通过命名空间进行标识。1.3.1 命名空间1.标准命名空间std是C+标准命名空间,由于C+标准库几乎都定义在std命名空间中,所以编写的所有C+程序都需要引入下列语句。要使用标准命名空间的内容必须先声明才能使用,声明方式如下:using namespace std;1.3.1 命名空间2.自定义命名空间自定义命名空间使用namespace定义,其格式如下:namespace空间名 /可以是变量、函数、类、其他命名空间1.3.1 命名空间命名空间的使用有三种方式:(1)命名空间名加
8、上作用域标识符“:”标识要使用的实体。在引用处指明变量所属的空间,例如,使用标准命名空间的标准输出和换行符,示例代码如下:std:coutC+std:endl;1.3.1 命名空间(2)使用using关键字,在要使用空间实体的上面,使用using关键字引入要使用的空间变量。例如,使用标准命名空间的标准输出,示例代码如下:using std:cout;cout”结合使用,用于读入用户输入,以空白(包括空格、回车、TAB)为分隔符。# 读入单个变量char c1,c2;cinc1;cinc2;# 读入多个变量string s,y;float f;cinsy; /一次读入多个相同类型的变量cinsf
9、; /一次读入多个不同类型的变量1.3.2 控制台输入输出2.coutcout与运算符“”结合使用,用于向控制台输出信息,称作标准输出对象或屏幕输出对象,但cout也可以重定向输出到磁盘文件。1.3.2 控制台输入输出(1)cout输出常量值cout10endl;coutaendl;coutC+endl;(2)cout输出变量值/输出单个变量int a =10;coutaendl; /输出多个变量int a = 10;char *str = abc;couta,strendl;1.3.2 控制台输入输出(3)cout输出指定格式的数据使用cout输出指定格式的数据时,可以通过C+标准库提供的标
10、志位和操作符控制格式,使用这些操作需要包含iomanip头文件。输出八进制、十进制、十六进制数据int a =10;coutoct:octaendl;/以八进制输出coutdec:decaendl;/以十进制输出couthex:hexaendl;/以十六进制输出1.3.2 控制台输入输出输出指定精度数据doublef=3.1415926;cout默认输出:fendl;cout精度控制setprecision(7)setiosflags(ios:fixed)fendl;输出指定域宽、对齐、填充方式的数据coutsetw(10)3.1415endl;coutsetw(10)setfill(0)3.
11、1415endl;coutsetw(10)setfill(0)setiosflags(ios:left)3.1415endl;coutsetw(10)setfill(-)setiosflags(ios:right)3.1415 y;1.3.3 类型增强3.枚举类型enumC语言中枚举类型只能是整数类型,且枚举变量可以用任意整数赋值,使用自由灵活。在C+中,枚举变量只能使用枚举出来的元素进行赋值。enumtemperatureWARM,COOL,HOT;enumtemperaturet=WARM;t=10;1.3.4 默认参数C+支持默认参数,即在定义或声明函数时给形参一个初始值,在调用函数时,
12、如果不传递实参就使用默认参数值。/例1-3 defaultPara.cppvoid add(int x,int y=1,int z=2) coutx+y+zendl;int main()add(1); add(1,2); add(1,2,3); return 0;1.3.4 默认参数在使用默认参数时需要注意以下规则:(1)默认参数只可在函数声明中出现一次,如果没有函数声明,只有函数定义,才可以在函数定义中设定。(2)默认参数赋值的顺序是自右向左,即如果一个参数设定了默认参数,则其右边不能存在未赋值的形参。(3)默认参数调用时,遵循参数调用顺序,即有参数传入它会先从左向右依次匹配。(4)默认参数
13、值可以是全局变量、全局常量,甚至可以是一个函数。1.3.5 函数重载重载(overload)函数就是在同一个作用域内几个函数名字相同但形参列表不同。/例1-4 overloadFunc.cppvoid add(int x, int y)cout int: x + y endl;void add(float x)cout float: 10 + x endl;double add(double x, double y)return x + y;int main()add(10.2); /一个实型参数add(1, 3); /两个整型参数return 0;1.3.5 函数重载当重载函数中的形参都是普
14、通形参,定义和调用不会出现问题,当重载函数有默认参数值时,需要注意参数传递的问题。注 意1.3.5 函数重载当使用具有默认参数的函数重载形式时,须注意防止调用的二义性,例如,下面的两个函数:int add(int x, int y = 1);void add(int x);当调用add()函数时,如果只有一个参数就会产生歧义,编译器无法确认调用哪一个函数,这就产生了调用的二义性。在使用时要杜绝一个函数既有默认参数又是重载函数,避免二义性的发生。1.3.6 引用引用是C+引入的新语言特性,它是某一变量的别名,C+引入引用的目的是简化指针的使用,灵活的使用引用可以使程序简洁高效。1.3.6 引用引
15、用就是给一个变量起一个别名,用“&”标识符来标识,其定义格式如下:数据类型 & 引用名 = 变量名;上述格式中,“&”并不是取地址操作符,而是起标识作用,标识所定义的标识符是一个引用。引用声明完成以后,定义的变量会有两个名称,定义多个则有多个名称。1.3.6 引用/例1-5 reference.cppint a=10;int &ra=a;cout变量a的地址hex&aendl;cout引用ra的地址:hex&raendl;cout引用ra的值:decraendl;1.3.6 引用在定义引用时需要注意以下方面: 引用在定义时必须初始化,且与变量类型保持一致。 引用在初始化时不能绑定常量值,如in
16、t &b = 10,是错误的。 引用在初始化后,其值就不能再更改,即不能用作其它变量的引用。 不能定义引用的引用,即不能定义引用再次引用一个引用。即int &rb=ra,是错误的用法。 有指针类型、数组类型的引用,而没有引用的指针和引用的数组。1.3.6 引用C+增加引用类型,主要的应用就是把它作为函数的参数,以扩充函数传递数据的功能。/例1-6 quote.cpp#include using namespace std;void exchange(int& x, int& y)int temp = x;x = y;y = temp;int main() int a, b; cout plea
17、se input two nums: a b; exchange(a, b); cout exchange: a b s2.size();1.3.7 字符串类C语言没有字符串这一数据类型,都是用字符数组处理字符串,C+支持C风格的字符串,还提供了一种自定义数据类型string,用于表示字符串,string是定义在头文件string中的类,使用前需要包含头文件string。使用string类型定义字符串,不必担心字符串长度、内存不足等情况,而且string类重载的运算符和成员函数足以完成字符串的处理操作。1.3.7 字符串类String定义字符串方式:string s1;s1=hello C+;
18、/第一种方式string s2=hello C+;/第二种方式string s3(hello C+);/第三种方式string s4(6,a);/第四种方式1.3.7 字符串类1.访问字符串中的字符string类重载了“”操作符,可以用索引访问和操作字符串中指定位置的字符。string s=hello,C+;s7=P;s8=P;2.字符串连接string重载了“+”运算符,可以使用“+”运算符连接两个string类型的字符串。string s1,s2;s1=我在学习;s2=C+;couts1+s2、s1s2;if(s1s2)cout字符串s1大于s2endl;else if (s1s2)cou
19、t字符串s2大于s1endl;elsecout字符串s1于s2相等endl;1.3.7 字符串类4.字符串长度计算string类也提供了一些获取字符串长度的函数,length()函数函数,用于获取字符串长度。string s = hello C+;coutlength():s.length()endl;1.3.7 字符串类5.字符串交换string类提供了成员函数swap(),用于交换两个字符串的值。string s1=hello C+;string s2=I Love China!;s1.swap(s2);string的成员函数swap()只能交换string类型的字符串,不能交换C语言风格
20、的字符串。1.3.8 new/delete1.newnew运算符用来申请一块连续的内存,其格式如下:new 数据类型(初始化列表);new在分配存储空间时指定了类型信息,并能根据初始化列表中给出的值进行初始化,new分配的内存空间直接可以使用,这个过程,称为new一个对象。new创建动态对象时不必为对象命名,直接指定数据类型即可。如果申请内存成功,返回一个类型指针;如果内存申请失败,则返回NULL。1.3.8 new/delete(1)创建基本数据类型对象使用new创建数据对象可以有不同的初始化方式:char* pc = new char; /申请空间存储char类型数据,内存中没有初始值in
21、t* pi = new int(10); /申请空间存储int类型数据,初始值为10float* pd = new float(); /申请空间存储float类型的数据,默认初始值为01.3.8 new/delete(2)创建数组类型对象new 数据类型数组长度;new数组时,后面可以加小括号(),括号中不可以指定任何初始值,由编译器提供默认初始值,不加小括号时不提供初始值。int *pi = new int10();char *pc = new char10;1.3.8 new/delete2.delete用new运算符分配内存,使用后要及时释放以免造成内存泄露,C+提供了delete运算符
22、释放new出来的内存空间,其格式如下:delete 指针名;delete运算符直接作用于指针就可以删除由new创建的对象,释放指针所指向的内存空间。但在释放数组对象时要在指针名前加上,其格式如下:delete 指针名;如果漏掉了,编译器在编译时无法发现错误,导致内存泄露。1.3.8 new/deleteint *pi = new int(10); /new 一个int对象,初始值为10cout*pi=*piendl;*pi = 20; /通过指针改变变量的值cout*pi = *piendl;char *pc = new char10;for (int i = 0;i 10;i+)pci =
23、i + 65; /向数组中存入元素for (int i = 0;i 10;i+)coutpci ;coutendl;delete pi; /释放int对象delete pc; /释放数组对象例1-7 allocMeorry.cpp1.3.9 extern “C”在C+程序中,可以使用extern “C”标注C语言代码,编译器会将extern “C”标注的代码以C语言的方式编译。externC / C语言代码1.3.9 extern “C”例1-8 mallocStr.h#include #include char* func(int,char*);例1-9 mallocStr.c#define
24、 _CRT_SECURE_NO_WARNINGS#includemallocStr.hchar* func(int size,char *str)char *p =malloc(size);strcpy(p,str);return p;1.3.9 extern “C”例1-10 main.cpp#ifdef _cplusplusextern C#endif #includemallocStr.h#ifdef _cplusplus#endif int main() char str=C+; char *p=func(sizeof(str)+1,str); coutpendl; free (p);
25、 return 0; 1.3.10 强制类型转换1.static_cast(expression)static_cast类型转换运算符可以实现下列转换: 基本数据类型之间的转换。 将任何类型转换为void类型。 把空指针转换成目标类型的指针。 用于类层次结构中基类和派生类之间指针或引用的转换。向上转换(派生类转换为基类)是安全的,向下转换(基类转为派生类)没有动态类型检查,是不安全的。1.3.10 强制类型转换int a=1;float b=3.14;a=static_cast(b); / 将float类型转为int类型b=static_cast(a); / 将void *p=NULL; in
26、t *q=NULL;q=p; / 空指针转为int类型,C语言允许,C+不允许p=q;q=static_cast(p); / 空指针转为int1.3.10 强制类型转换2.reinterpret_cast(expression)reinterpret_cast通常为操作数的位模式提供较底层的重新解释,重新解释指的是将二进制数据重新解释,在向上转换或者向下转换不可以进行隐式转换时,则需要重新解释类型转换,reinterpret_cast要转换的type类型必须是指针类型、引用或算术类型。1.3.10 强制类型转换char c = a;int d = reinterpret_cast(c);int
27、 *p=NULL; float *q=NULL;p = q; /C语言允许,C+语言不允许q = p; /C语言允许,C+语言不允许p = static_cast(q); /static_cast无法转换q = static_cast(p); /static_cast无法转换p = reinterpret_cast(q);q = reinterpret_cast(p);1.3.10 强制类型转换3.const_cast(expression)const_cast用于移除const对象的引用或指针具有的常量性质,可以去除const对引用和指针的限定,const_cast只能用于转换指针或引用。C
28、+中使用const修饰的变量只能被读取而无法被修改,而C语言中能通过指针方式修改const修饰的变量。为了兼容C语言,具有C语言的功能而比C语言更完善,C+语言提出了const_cast转换方式,能够修改const修饰的变量。1.3.10 强制类型转换int num = 100;const int* p1 = #/将常量指针转换为普通类型指针,去除const属性 int* p2 = const_cast(p1);*p2 = 200;int a=100;const int & ra=a;/将常量引用转化为普通类型引用,去除const属性const_cast(ra)=200;1.3.10
29、强制类型转换4.dynamic_cast(expression)dynamic_cast用于运行时检查类型转换是否安全,可以在运行期间确定类型,如类的指针、类的引用和void*。dynamic_cast主要应用于类层次间的向上转换和向下转换,以及类之间的交叉转换。在类层次间进行上行转换时,它和static_cast作用一致,与static_cast相比,dynamic_cast能够在运行时检查类型转换是否安全。当向下转换时,基类指针或引用指向派生类对象时,dynamic_cast运算符会返回转换后类型的指针,这样的转换是安全的。如果基类指针或引用没有指向派生类对象则转换是不安全的,并返回NUL
30、L。多学一招:Bjarne Stroustrup对编写C+的建议 1.在 C+中几乎不需要用宏。2.用 const 或 enum 定义显式的常量。3.用 inline 避免函数调用的额外开销。4.用模板去定义函数或类型。5.用 namespace 去避免命名冲突。6.确保声明的变量初始化,而不要在需要使用之前去声明。多学一招:Bjarne Stroustrup对编写C+的建议 7.使用new和delete会比malloc()和free()函数更好,对于realloc()函数,可以用vector()代替。8.避免使用 void*、指针算术、联合和强制转换。9.尽量少用数组和 C 风格的字符串,标
31、准库中的 string 和 vector 可以简化程序。10.试着将程序考虑为一组由类和对象表示的相互作用的概念。1.4 本章小结本章首先讲解了C+语言的发展历史、特点,然后带领大家编写了第一个C+程序,最后讲解了C+语言相对于C语言在基础语法上的扩充,如命名空间、类型增强、默认参数、引用等新知识点。通过本章的学习,大家会对C+语言有基础的认识,在编写C+语言程序中使用这些特性,为后续学习新的内容奠定基础。第2章 类与对象 this指针 构造函数 析构函数 类的定义 对象的创建与使用 类的封装 拷贝构造函数 const与static修饰类成员 友元2.1 面向对象程序设计思想在程序中使用对象映
32、射现实中的事物,利用对象之间的关系描述事物之间的联系,这种思想就是面向对象。面向对象则是把构成问题的事物按照一定规则划分为多个独立的对象,然后通过调用对象的方法解决问题。当然,一个应用程序会包含多个对象,通过多个对象的相互配合即可实现应用程序所需的功能,这样当应用程序功能发生变动时,只需要修改个别对象就可以了,使代码更容易维护。2.1 面向对象程序设计思想面向对象三大特征封装继承多态2.1 面向对象程序设计思想1.封装封装是面向对象程序设计最重要的特征之一,封装就是隐藏,它将数据和数据处理过程封装成一个整体,以实现独立性很强的模块,避免外界直接访问对象属性而造成耦合度过高及过度依赖。2.1 面
33、向对象程序设计思想2.继承继承主要描述的是类与类之间的关系,通过继承无须重新编写原有类,就能对原有类的功能进行扩展。继承2.1 面向对象程序设计思想3.多态多态是事物的多种表现形态。例如,上课铃声响起后,各科老师准备去不同的班级上课,上体育课的班级在操场站好了队等体育老师发布口令、上文化课的学生听到铃声后回到各自的班级,这就是多态。在面向对象程序设计中,多态就是不同的对象对同一个消息产生不同的行为。2.2.1 类的定义类是对象的抽象,是一种自定义数据类型,它用于描述一组对象的共同属性和行为。类的定义格式如下所示:class 类名权限控制符: 成员;2.2.1 类的定义 class是定义类的关键
34、字。 类名是类的标识符,其命名遵循标识符的命名规范。 类名后面的一对大括号,用于包含类的成员,类的所有成员要在这一对大括号中声明。类中可以定义成员变量(描述对象特征)和成员函数(描述对象行为)。 声明类的成员时,通常需要使用权限控制符限定成员的访问规则,权限控制符包括public、private和protected,这三种权限控制符的权限依次递减。 大括号的后面的一个分号“;”表示类定义的结束。2.2.1 类的定义class Student/定义类Studentpublic:/公有权限 void study();/声明表示学习的成员函数 void exam();/声明表示考试的成员函数priv
35、ate:/私有权限 string _name;/姓名 int _age;/年龄;代码定义了一个简单的学生类Student,该类中有两个成员变量:_name、_age,它们是类的私有成员;除了成员变量,该类还定义了两个成员函数:study()和exam(),它们是类的公有成员。2.2.1 类的定义通常情况下,类的成员函数在类中声明,在类外实现。在类外实现成员函数,必须在返回值之后、函数名之前加上所属的类作用域,即“类名:”,表示函数属于哪个类。其格式如下所示:返回值类型 类名:函数名称(参数列表)函数体2.2.1 类的定义例如,实现类Student的成员函数,示例代码如下:void Studen
36、t:study()/类外实现studey()成员函数cout 学习C+ endl;void Student:exam()/类外实现exam()成员函数cout C+考试成绩100分 endl;2.2.1 类的定义类的访问权限控制符: public(公有类型):被public修饰的成员也称为公有成员。公有成员是类的外部接口,可以被所属类的成员函数、类对象、派生类对象、友元函数、友元类访问。 private(私有类型):被private修饰的成员称为私有成员,只能被所属类的成员函数、友元函数、友元类访问。 protected(保护类型):被protected修饰的成员称为保护成员,其访问权限介于私
37、有和公有之间,可以被所属类的成员函数、派生类、友元类和友元函数访问。2.2.2 对象的创建与使用定义了类,就相当于定义了一个数据类型,它与int、char等数据类型是一样的,可以定义具体的变量,使用类定义的变量通常称为该类的对象。对象的定义格式如下所示:类名 对象名;Student stu; 2.2.2 对象的创建与使用创建了类的对象,系统就要为对象分配内存空间,用于存储对象成员。在存储时,对象的成员变量都有独自的内存空间,但成员函数是所有对象共享的。2.2.2 对象的创建与使用对象的成员变量和成员函数的访问可以通过“.”运算符实现。对象名.成员变量对象名.成员函数对象的成员访问2.2.2 对
38、象的创建与使用class Student public: void study(); void exam(); string _name; int _age;void Student:study() cout 学习C+ endl; void Student:exam() cout C+考试成绩100分 endl;int main() Student stu; stu._name = 张三; stu._age = -20; cout stu._name stu._age 岁 endl; stu.study(); stu.exam(); return 0;例2-1 Student.cpp2.3 封
39、装C+中的封装是通过类实现的,通过类把具体事物抽象为一个由属性和操作行为结合的独立单位,通过类的对象对属性和行为进行操作。在类的封装设计中通过权限控制方式实现类成员的访问,目的是为了隐藏对象的内部实现细节,只对外提供访问的接口。封 装2.3 封装通过权限控制符可以限制外界对类的成员变量的访问,将对象的状态信息隐藏在对象内部,通过类提供的函数(接口)实现对类中成员的访问。其具体实现过程为:在定义类时,将类中的成员变量设置为私有或保护属性,即使用private或protected关键字修饰成员变量。使用类提供的公有成员函数(public修饰的成员函数),如getXxx()函数和用于设置成员变量值的
40、setXxx()函数,操作成员变量的值。封 装2.3 封装/例2-2 package.cppclass Studentpublic: void study(); void exam(); void setName(string name); void setAge(int age); string getName(); int getAge();private: string _name; int _age;void Student:study() cout 学习C+ endl;void Student:exam() cout C+考试成绩100分 endl;void Student:setN
41、ame(string name) _name = name;void Student:setAge(int age) if (age 100) cout _name 年龄输入错误 endl; _age = 0; else _age = age;string Student:getName()return _name;int Student:getAge()return _age; 2.3 封装int main()Student stu;/创建Student类对象stustu.setName(张三);/设置对象stu的姓名stu.setAge(-20);/设置对象stu的年龄cout stu.g
42、etName() stu.getAge() 岁 endl;stu.study();/调用成员函数study()stu.exam();/调用成员函数exam() Student stu1;/创建Student类对象stu1stu1.setName(李四);stu1.setAge(22);cout stu1.getName() stu1.getAge() 岁 _name = name;string Student:getName(Student* this)return this-_name;2.4 this指针上述过程是隐含的,由编译器完成。当对象stu调用成员函数时,指向对象stu的this指
43、针作为成员函数的第一个参数,在成员函数内部使用对象属性时,编译器会通过this指针访问该属性。2.4 this指针在实现类的成员函数时,如果形参与类的属性重名,可以用this指针解决。例如,Student类的成员变量为name和age,则成员变量和setName()函数、setAge()函数在赋值时无法区分形参和实参,可使用this指针:void Student:setName(string name)this-_name = name; string Student:getName()return this-_name; 如果类的成员函数返回值为一个对象,则可以使用return *this返
44、回对象本身。2.5 构造函数构造函数是类的特殊成员函数,用于初始化对象。构造函数在创建对象时由编译器自动调用。C+中的每个类至少要有一个构造函数,如果类中没有定义构造函数,系统会提供一个默认的无参构造函数,默认的无参构造函数体也为空,不具有实际的初始化意义。因此,在C+程序中要显式定义构造函数。2.5.1 自定义构造函数构造函数是类的特殊成员函数,C+编译器严格规定了构造函数的接口形式,其定义格式如下所示:class 类名权限控制符:构造函数名(参数列表)函数体 /其他成员;2.5.1 自定义构造函数 构造函数名称必须与类名相同。 构造函数名称的前面不需要设置返回值类型。 构造函数中无返回值,
45、不能使用return返回。 构造函数的成员权限控制符一般设置为public。2.5.1 自定义构造函数1.自定义无参构造函数自定义无参构造函数时,可以在函数内部直接给成员变量赋值。/例2-3 noPara.cppclass Clockpublic: Clock(); void showTime();private: int _hour; int _min; int _sec; ;Clock:Clock() _hour=0; _min=0; _sec=0; void Clock:showTime() coutsetw(2)setfill(0)_hour: setw(2)setfill(0)_mi
46、n: setw(2)setfill(0)_secendl;int main()Clock clock;coutclock:;clock.showTime();return 0;2.5.1 自定义构造函数2.自定义有参构造函数如果希望在创建对象时提供有效的初始值,可以通过定义带参数的构造函数实现。/例2-4 parameter.cppclass Clock/定义时钟类Clockpublic:Clock(int hour, int min, int sec); /声明有参构造函数void showTime();/用于显示时间的成员函数2.5.1 自定义构造函数private:int _hour;
47、int _min; int _sec; /声明时分秒变量;Clock:Clock(int hour, int min, int sec) /类外实现有参构造函数_hour=hour;_min=min; _sec=sec;void Clock:showTime() /类外实现成员函数coutsetw(2)setfill(0)_hour:setw(2)setfill(0)_min :setw(2)setfill(0)_secendl; 2.5.1 自定义构造函数int main()Clock clock1(10,20,30); /创建对象clock1,传入初始值coutclock1:;clock1
48、.showTime(); /通过对象调用成员函数showTime()显示时间Clock clock2(22,16,12); /创建对象clock2,传入初始值coutclock2:;clock2.showTime(); /通过对象调用成员函数showTime()显示时间return 0;2.5.1 自定义构造函数在实现构造函数时,还可以通过“:”运算符,在构造函数后面初始化成员变量,这种方式称为列表初始化,其格式如下所示:类:构造函数(参数列表): 成员变量1(参数1), 成员变量的2(参数2), 成员变量n(参数n)构造函数体Clock:Clock(int hour, int min, in
49、t sec):_hour(hour),_min(min),_sec(sec)2.5.2 重载构造函数在C+中,构造函数允许重载,例如,Clock类可以定义多个构造函数。2.5.2 重载构造函数class Clock /定义时钟类public:Clock();Clock(int hour);Clock(int hour, int min);Clock(int hour, int min, int sec);void showTime();/显示时间private:int _hour;/小时int _min;/分钟int _sec;/秒;2.5.2 重载构造函数当定义具有默认参数的重载构造函数时,
50、要防止调用的二义性。/例2-5 overload.cppclass Clockpublic: Clock(int hour, int min); Clock(int hour, int min, int sec=0); /有默认参数 void showTime();private: int _hour; int _min; int _sec; ;Clock:Clock(int hour, int min):_hour(hour),_min(min) cout调用两个参数的构造函数endl; _sec=10; 2.5.2 重载构造函数Clock:Clock(int hour, int min,
51、int sec=0) cout调用三个参数的构造函数endl; _hour=hour; _min=min; _sec=sec;void Clock:showTime() coutsetw(2)setfill(0)_hour: setw(2)setfill(0)_min: setw(2)setfill(0)_secendl; int main() Clock clock(8,0); coutclock:; clock.showTime(); return 0;2.5.2 重载构造函数运行上述代码,由于构造函数调用不明确,程序会报错。2.5.2 重载构造函数上述代码中,Clock类定义了两个重载构
52、造函数,其中,第一个构造函数有两个参数;第二个构造函数有三个参数,最后一个参数有一个默认值。在main()函数中创建一个对象clock,传入两个参数,编译器无法确认调用的是哪个构造函数,因此程序会报错。2.5.3 含有类成员对象的构造函数C+中允许将一个已定义的对象作为另一个类的成员变量,即类中的成员变量可以是其他类的对象,这样的成员变量称为类的子对象或成员对象。2.5.3 含有类成员对象的构造函数含有成员对象的类的形式如下所示:class BA a;/对象a作为类B的成员变量2.5.3 含有类成员对象的构造函数创建含有成员对象的对象时,先执行成员对象的构造函数,再执行类的构造函数。例如,上述
53、格式中,类B包含一个类A对象作为成员变量,在创建类B对象时,先执行类A的构造函数,将类A对象创建出来,再执行类B的构造函数,创建类B对象。如果类A构造函数有参数,其参数要从类B的构造函数中传入,且必须以“:”运算符初始化类A对象。2.5.3 含有类成员对象的构造函数/例2-6 Student.cppclass Birthpublic:Birth(int year,int month, int day); void show();private:int _year; int _month; int _day;Birth:Birth(int year, int month, int day):_y
54、ear(year),_month(month),_day(day)coutBirth类构造函数endl; void Birth:show()cout出生日期:_year-_month-_dayendl;2.5.3 含有类成员对象的构造函数class Student /定义学生类Studentpublic:Student(string name, int id, int year, int month, int day);void show();private:string _name; int _id; Birth birth; ;Student:Student(string name, in
55、t id, int year, int month, int day):birth(year,month,day)coutStudent类构造函数endl;_name=name; id=id; void Student:show()cout姓名:_nameendl;cout学号:_idendl;birth.show(); 2.5.3 含有类成员对象的构造函数int main() Student stu(lili,10002,2000,1,1);/创建学生对象stustu.show();/显示学生信息return 0;2.5.3 含有类成员对象的构造函数上述代码,定义了两个类:日期类Birth:
56、该类中有三个成员变量:_year、_month、_day,并且定义了有参数的构造函数;学生类Student:该类有三个成员变量:_name、_id、birth,其中,birth是类Birth的对象。此外,Student类还定义了一个构造函数。由于成员对象birth的构造函数有三个参数,这三个参数要从类Student的构造函数中获取,因此Student类的构造函数共有5个参数。2.5.3 含有类成员对象的构造函数在实现Student类的构造函数,birth成员对象必须通过“:”运算符在Student构造函数后面初始化,无法在Student构造函数体中赋值。在main()函数中创建Student类
57、对象stu,可以通过对象stu调用成员函数show()显示学生信息,包括学生出生日期。2.6 析构函数创建对象时,系统会为对象分配所需要的内存空间等资源,当程序结束或对象被释放时,系统为对象分配的资源也需要回收,以便可以重新分配给其他对象使用。在C+中,对象资源的释放通过析构函数完成。析构函数的作用是在对象被释放之前,完成一些清理工作。析构函数调用完成之后,对象占用的资源也被释放,对象也就消失了。2.6 析构函数与构造函数一样,析构函数也是类的一个特殊成员函数,其定义格式如下所示:class 类名析构函数名称();2.6 析构函数关于析构函数的定义,有以下注意事项: 析构函数的名称与类名相同,
58、在析构函数名称之前添加“”符号。 析构函数没有参数。因为没有参数,所以析构函数不能重载,一个类中只有一个析构函数。 析构函数没有返回值,不能在析构函数名称前添加任何返回值类型。在析构函数内部,也不能通过return返回任何值。2.6 析构函数当程序结束时,编译器会自动调用析构函数完成对象的清理工作,如果类中没有定义析构函数,编译器会提供一个默认的析构函数,但默认的析构函数只能完成栈上对象的资源清理,无法完成堆内存对象的资源清理。因此,在程序中往往需要自定义析构函数。2.6 析构函数析构函数的调用情况主要有以下几种:(1)在一个函数中定义了一个对象,当函数调用结束时,对象应当被释放,对象释放之前
59、,编译器会调用析构函数释放资源。(2)static修饰的对象和全局对象,只有在程序结束时才会调用析构函数。(3)new运算符创建的对象,在调用delete释放对象时,编译器会调用析构函数释放资源。2.6 析构函数析构函数的调用顺序与构造函数的调用顺序是相反的。在构造对象和析构对象时,C+遵循的原则是:先构造的后析构,后构造的先析构。注 意2.6 析构函数/例2-7 Rabbit.cppclass Rabbit/定义兔子类Rabbitpublic:Rabbit(string name,const char *pf);void eat();Rabbit();private:string _name
60、;char *_food;2.6 析构函数Rabbit:Rabbit(string name, const char* pf)cout调用构造函数endl;_name=name;_food=new char50;memset(_food,0,50);strcpy(_food,pf);void Rabbit:eat() cout_name is eating _foodendl; Rabbit:Rabbit()cout调用析构函数,析构_nameendl;if(_food != NULL)delete _food; 2.6 析构函数int main()Rabbit A(A,luobo);A.ea
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 天津滨海汽车工程职业学院《舞弊审计》2023-2024学年第一学期期末试卷
- 物业街道备案合同范例
- 彩钢安全合同范例
- 仪器定制合同范例
- 疾病调理签约合同范例
- 用电安全协议合同范例
- 太原恒大停车位合同范例
- 全职签劳务合同范例
- 四年级语文下册 第七单元 口语交际:自我介绍教学实录 新人教版
- 2025年漯河货运资格证题库及答案大全
- 【MOOC】英文技术写作-东南大学 中国大学慕课MOOC答案
- 电气工程及其自动化职业规划课件
- 辐射与防护学习通超星期末考试答案章节答案2024年
- 2023年新高考(新课标)全国2卷数学试题真题(含答案解析)
- 建筑施工安全生产治本攻坚三年行动方案(2024-2026年)
- 大学生助农直播创业计划书
- 2-05SFG04 防空地下室室外出入口部钢结构装配式防倒塌棚架结构设计
- 石灰窑烘炉及开炉方案
- 复苏囊的使用PPT
- 教学论文】《自制教具应用于初中物理有效教学的研究》课题研究报告【教师职称评定】
- 串宫压运推算表
评论
0/150
提交评论