




已阅读5页,还剩173页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C+程序设计基础,第7章 类与对象 北京邮电大学信通院 方莉 ,2,第7章 类与对象,类是实现C+面向对象程序设计的基础。 面向对象程序设计的基本特点有:抽象、封装、继承和多态。 类把数据和函数封装在一起,是C+封装的基本单元。 本章主要内容 类的使用、定义和实现 面向对象分析和面向对象设计,7.1 类和对象的定义 7.2 对象的使用 7.3 构造函数 7.4 析构函数 7.5 类的静态成员 7.6 类成员的保护和使用 7.7 运算符重载 7.8 类的组合 7.9 面向对象分析和设计,第7章 类与对象,4,7.1 类和对象的定义,一个类表示现实生活中的一类事物,比如“学生”, 事物有相应的特征或属性,它们就是类的数据成员; 事物可能有行为动作,也可能被某些行为动作所操作,这些都用函数来实现,这些函数和类有着不可分割的关系,是构成类的函数成员,或者叫成员函数。 在C+中,类实际上相当于一种用户自定义的数据类型。,5,在定义了类类型后,就可以定义该类型的变量,这个变量就称为类的对象(或实例)。 对象是一类事物中的一个具体的个体。 从程序设计的角度来看,对象就相当于变量。,7.1 类和对象的定义,6,举例:,class Student /类的定义 private: int id; char20 name; int age; float score; public: void getscore() void printstu() ;,7.1 类和对象的定义,7,7.1.1 使用类对象,如果已经知道某个类的功能和接口函数,就可以使用它了。先定义类对象,通过对象调用接口函数实现一定的功能。 class Student stu01; /class也可以省略不写 Student stu01; stu01.getscore(); stu01.printstu(); 这个过程的本质是:根据对象所需要完成的任务,向对象发送消息。对象收到消息后,调用接口中的相应的函数,完成它的功能。对象只需要知道“做什么”,具体工作由成员函数来完成。,8,class Student /类的定义 private: int id; char name 20; float score; public: void GetData(); void PrintData(); ;,类的声明:具体说明类的组成 class 类名 private: /数据成员 protected: /保护成员 public: /成员函数 ; 一般写在类的.h文件中,也可以写在类的.cpp文件之首。,7.1.2 类的声明,9,类实际上是一种用户自定义的数据类型。 比较:,struct student int id; char20 name; float score; ;,class Student private: int id; char name20; float score; public: void GetData(); void PrintData(); ;,同是自定义的类型。 在无显式声明时,结构体的成员是公有的,类的成员是私有的。,7.1.2 类的声明,10,分析: 任何一个时钟应该有时、分、秒的值,这就是时钟的属性特征;时钟的操作应该有设置时间、显示时间等。画出时钟类的标记图如下:,例: 要声明一个时钟类,11,举例: class Clock public: void SetTime(int newH,int newM,int newS); void ShowTime(); private: int Hour; int Minute; int Second; ;,7.1.2 类的声明,12,举例: class Point public: void SetXY(int x, int y); void GetXY(int ,7.1.2 类的声明,13,关键字public、protected、private说明类成员的访问控制属性。 私有(private)成员只允许本类的成员函数来访问; 公有(public)成员是类对外的接口,在类声明和类(函数)实现之后,类的对象可以访问公有成员。 保护型(protected)成员,对于类外其它函数,其可访问性和私有成员的性质相似。,7.1.2 类的声明,14,关于访问控制属性,注意: 在类声明中,三种访问控制属性,可以按任意次序出现,也可以不出现。public等关键字也可以多次出现,但是一个成员只能具有一种访问控制属性。 如果不写访问控制属性关键字,默认的是private。在书写时通常习惯将公有类型放在最前面,这样便于阅读,因为它们是外部访问时所要了解的。 一般情况下,一个类的数据成员应该声明为私有成员,这样封装性较好。一个类应该有一些公有的函数成员,作为对外的接口,否则别的代码无法访问类。,7.1.2 类的声明,15,“类的成员”既可以是数据成员,也可以是成员函数的原型。 数据成员,表示类的属性,声明方式与一般变量相同。 成员函数,描述类的对象可以进行的操作,一般在类中声明原型,在类声明之外定义函数的具体实现。,7.1.2 类的声明,16,类的成员函数描述的是类的行为或操作。 在类声明中,声明函数的原型。(类的声明文件.h文件) 函数的具体实现一般写在类声明之外。(类的实现文件.cpp文件) 在类的外部定义成员函数的语法形式为: 返回值类型 类名:成员函数名(参数表) 函数体 ,7.1.3 类的成员函数,17,例: 时钟类Clock的成员函数的实现: void Clock:SetTime(int newH,int newM,int newS) Hour=newH; Minute=newM; Second=newS; void Clock:ShowTime() coutHour“:“Minute“:“Secondendl; ,7.1.3 类的成员函数,18,class Clock public: void SetTime(int NewH, int NewM, int NewS); void ShowTime( ); private: int Hour, Minute, Second; ;,void Clock:SetTime(int NewH, int NewM, int NewS) Hour=NewH; Minute=NewM; Second=NewS; void Clock:ShowTime() coutHour“:”Minute“:”Secondendl; ,Clock类的声明和实现,19,成员函数描述类的行为(或服务、操作);实现程序的算法,是对类封装的数据进行操作的唯一途径。 在类定义中说明原型(一般在.h文件中),在类的实现文件(.cpp)中定义函数体,并在函数名前使用类名加以限定,标示它与类之间的关系。也可以直接在类中定义函数体,形成内联成员函数。 允许定义重载函数和带缺省形参值的成员函数。 在声明成员函数时,可以控制访问权限;一般将成员函数设为公有型的。,7.1.3 类的成员函数,20,/Tdate.h 类的声明文件 class Tdate public: void Set(int m,int d,int y); /置日期值 int IsLeapYear(); /判是否闰年 void Print(); /输出日期值 private: int month; int day; int year; ;,21,/Tdate.cpp 类的实现文件 void Tdate:Set(int m,int d,int y) month=m; day=d; year=y; int Tdate: IsLeapYear() return (year%4=0 ,22,内联函数: 如果在类的内部定义成员函数的具体实现,则该成员函数为内联成员函数。 函数定义时没有任何的附加说明,所以称为隐式声明的内联成员。 显示内联函数 (用 inline),7.1.3 类的成员函数,23,class Point public: void SetXY(int x, int y) m_x=x; m_y=y; void GetXY(int ,7.1.3 类的成员函数,24,class Clock public: void SetTime(int NewH, int NewM, int NewS); void ShowTime( ); private: int Hour, Minute, Second; ;,inline void Clock:SetTime(int NewH, int NewM, int NewS) Hour=NewH; Minute=NewM; Second=NewS; inline void Clock:ShowTime() coutHour“:”Minute“:”Secondendl;,显式声明的内联函数,7.1.3 类的成员函数,25,带默认参数值的成员函数 类的成员函数也可以有默认形参值,其调用规则同普通函数相同。 例如时钟类的SetTime()函数,使用默认值: void Clock:SetTime(int newH=0,int newM=0, int newS=0) Hour=newH; Minute=newM; Second=newS; ,7.1.3 类的成员函数,26,重载函数 成员函数可以用与普通函数同样的方法重载。 例:class Point public: void Set(int x, int y); void Set(int x, int y,int color); void Get(int ,7.1.3 类的成员函数,27,注意,类名是成员函数名的一部分,所以一个类的成员函数与另一个类的成员函数即使同名,也不能认为是重载。,class Clock public: void Set (int NewH, int NewM, int NewS); void Show ( ); private: int Hour, Minute, Second; ;,class Point public: void Set(int x, int y); void Get(int ,7.1.3 类的成员函数,28,对象是一类事物中的个体,从程序设计的角度来看,对象就相当于变量。 定义一个对象和定义一个一般变量相同。 类名称 对象名称 例 Clock ck1; Point point1;,7.1.4 对象,29,定义变量时要分配存储空间,同样,定义一个对象时要分配存储空间,一个对象所占的内存空间是类的数据成员所占的空间总和。类的成员函数存放在代码区,不占内存空间。 类的成员是抽象的,对象的成员才是具体的。类的数据成员都不会有具体的属性值。只有对象的成员才会有具体的属性值。,7.1.4 对象,30,对象的使用:根据类的功能和接口函数,定义对象,通过对象调用接口函数实现一定的功能。 声明了类及其对象,在类的外部(即在类定义和成员函数的实现代码之外),就可以访问对象的公有成员(包括数据成员和函数成员)了。 语法形式为: 对象名. 公有数据成员 对象名.公有成员函数名(参数表),7.1.4 对象,31,使用对象的过程: 根据对象所需要完成的任务,向对象发送消息。 对象收到消息后,调用接口中的相应的函数,完成它的功能。 对象只需要知道“做什么”,具体工作由成员函数来完成。 例: class student stu1; 或 student stu1; stu1.GetData(); stu1.PrintData();,7.1.4 对象,class Student /类的定义 private: int id; char name 20; float score; public: void GetData(); void PrintData(); ;,32,例如,在主函数中定义了Clock类的对象: void main() Clock myclock; myclock.SetTime(12, 5, 0); myclock.ShowTime(); ,执行main()函数时的内存分配情况,33,在类的外部,只能通过对象访问类的公有成员;在类的成员函数内部,可以直接访问类的所有成员,这就实现了对访问范围的有效控制。,void Clock:SetTime( int newH=0, int newM=0, int newS=0) Hour=newH; minute=newM; Second=newS; ,class Clock public: void Set (int NewH, int NewM, int NewS); void Show ( ); private: int Hour, Minute, Second; ;,void main() Clock myclock; myclock.SetTime(12,5, 0); myclock.ShowTime(); ,7.1.4 对象,34,类作用域是指类定义和相应的成员函数定义的范围,通俗地称为类的内部。 一个类的全部成员都是一个整体的相关部分。 一个类的所有成员位于这个类的作用域内,在该范围内,一个类的成员函数对本类的其它成员具有无限制的访问权。,7.1.5 类的作用域与可见性,35,例7.2:编程测试类的作用域范围。 #include using namespace std; class Sample private: int a; void fa();,protected: float b; void fb(); public: char c; void set(); void display(); ;,7.1.5 类的作用域与可见性,36,void Sample:fa() cout “In function fa“endl; couta“ “b“ “cendl; void Sample:fb() cout “In function fb“endl; couta“ “b“ “cendl; ,7.1.5 类的作用域与可见性,37,void Sample:set() a=10; b=5.5; c=K; void Sample:display() cout “In function display“endl; fa(); ,在类的成员函数里,可以访问类的任何成员,7.1.5 类的作用域与可见性,38,void main() Sample s; / s.a=10; /编译时会出错,在类的外部不能访问类的私有成员 / s.b=5.5;/编译时会出错,在类的外部不能访问类的保护成员 s.c=K; s.set(); / s.fa();/编译时会出错,在类的外部不能访问类的私有成员 / s.fb();/编译时会出错,在类的外部不能访问类的保护成员 s.display(); ,7.1.5 类的作用域与可见性,39,类名实际是个类型名,允许类名与其它变量名或函数名相同。 在类的内部,外部与类名同名的全局变量名或函数名不可见。 在一个函数内,同名的类名和变量名可以同时使用,都是可见的。,7.1.5 类的作用域与可见性,40,例:若Sample类已定义,以下函数的定义是没有问题的: void func( ) class Sample a; /定义对象时要用到类名,加前缀class int Sample=10; /变量名和类名相同 Sample+; / 但是从程序可读性考虑,一般还是不要让类名和其他变量名、函数名用同样的名字。,7.1.5 类的作用域与可见性,41,要声明一个时钟类,任何一个时钟都应该有时、分、秒的值,这就是时钟的属性特征;时钟的操作应该有设置时间、显示时间等。,7.1.6 时钟类举例,42,/声明时钟类的头文件:Clock.h #include using namespace std; class Clock /类的声明 public: void SetTime(int newH=0,int newM=0,int newS=0); void ShowTime(); void ShowTime(int n); private: int Hour; int Minute; int Second; ;,7.1.6 时钟类举例,43,/实现类成员函数的源文件:Clock.cpp #include “Clock.h“ void Clock:SetTime(int newH,int newM,int newS) /SetTime()函数定义 Hour=newH; Minute=newM; Second=newS; void Clock:ShowTime() /ShowTime()函数定义 coutHour“:“Minute“:“Secondendl; void Clock:ShowTime(int n) /重载函数的定义 coutHour“点“Minute“分“Second“秒“endl; ,7.1.6 时钟类举例,44,/测试应用程序:7-1.cpp #include “Clock.h“ void main() Clock myclock; /类的对象 myclock.SetTime(12, 5, 0); /设置时间 myclock.ShowTime(); /第一种方式显示时间 myclock.ShowTime(1);/第二种方式显示时间 ,7.1.6 时钟类举例,7.1 类和对象的定义 7.2 对象的使用 7.3 构造函数 7.4 析构函数 7.5 类的静态成员 7.6 类成员的保护和使用 7.7 运算符重载 7.8 类的组合 7.9 面向对象分析和设计,第7章 类与对象,46,对象是类的一个具体的实例,类和对象的关系相当于普遍与特殊的关系。在C+中,类是一个自定义的数据类型,对象是该数据类型的一个变量。 在大型程序开发中,类的定义和实现可以作为一个完整的程序模块,在其它的程序模块中可以定义对象,通过对象访问公有成员函数,模块与模块之间的接口就是那些公有成员函数。,7.2 对象的使用,47,定义一个全局的对象 可以在函数体中定义一个局部的对象 动态地从堆中申请空间来创建一个对象 可以定义对象数组 使用对象作为函数的参数与返回值。,7.2 对象的使用,48,声明对象指针的一般语法形式为: 类名* 对象指针名; 使用对象指针访问对象的成员,语法形式为: 对象指针名-公有成员; 例如: Clock c; /在栈中分配Clock型存储空间 Clock* pc1=new Clock;/在堆中分配Clock型存储空间 Clock* pc2=,1. 对象指针,49,void main() Clock* pmyclock=new Clock; pmyclock-SetTime(12, 5, 0); pmyclock-ShowTime(); delete pmyclock; ,1.对象指针,50,问:一个类中所有对象调用的成员函数都执行同一段代码。那么,成员函数又是怎么识别当前是那个对象在访问呢? 答:this指针指出了成员函数当前所操作的数据所属的对象。不同的对象调用成员函数时,this指针将指向不同的对象,也就可以访问不同对象的数据成员。,2.this指针,51,如果通过某个对象调用其公有成员,则此时该对象被称为当前对象,系统用this指针指向当前对象。 成员函数被调用时,它除了得到实际参数外,还得到了指向当前对象的this指针。 例如: Clock c1,c2; c1.SetTime(12,5,0);/此时this指向c1 c1.ShowTime(); c2.SetTime(11,4,2); /此时this指向c2 c2.ShowTime();,2.this指针,52,在成员函数内部,所有对类成员的访问都隐含地加上前缀this-。所以函数SetTime()的实现相当于: void Clock:SetTime(Clock * this,int newH,int newM,int newS) this-Hour=newH; /但是不能在Hour前加对象名 this-Minute=newM; this-Second=newS; ,2.this指针,53,对象数组的元素是对象,不仅具有数据成员,而且还有函数成员,可以通过数组元素调用成员函数。,3.对象数组,54,/例7.3 使用对象数组 #include using namespace std; class student private: int id; char name20; int age; float score; public: void set(int, char*, int, float); void printstu(); ;,3.对象数组,例 7.3: 定义学生类student, 数据成员包括:学号、姓名、年龄、成绩; 函数成员有设置值和输出显示。 在主函数中定义学生数组,表示多个学生,给每个学生设置值,然后输出显示。,55,void student:set(int i, char* c, int a, float s) id = i; strcpy(name, c); age = a; score = s; void student: printstu(); cout“学号:“id“ 姓名:“name; cout“ 年龄:“age“ 成绩:“scoreendl; ,3.对象数组,56,void main() student stu5; /对象数组 stu0.set(1,“wang“,18, 86); /设置数组中每个对象 stu1.set(2,“Li“,18, 72); stu2.set(3,“zhao“,18, 80); stu3.set(4,“guo“,18, 85); stu4.set(5,“meng“,18, 75); for(int i=0; i5; i+) stui.printstu(); /显示每个对象 ,3.对象数组,57,可以将对象作为参数传递给一个函数 直接用对象作为参数,调用函数时,进行值传递,实参的值要复制给形参; 如果类的数据成员较多时,需要一一复制,这种参数传递方式效率不高,可以使用对象指针或对象引用方式来传递函数参数。 可以从函数返回一个对象。,4.对象用做函数的参数和返回值,58,/Tdate.h:Tdate类声明 #include using namespace std; class Tdate public: void Set(int,int,int); /成员函数的声明 int IsLeapYear(); void Print(); private: int month; int day; int year; ;,例7.4 使用对象作为函数的参数,59,/Tdate.cpp:Tdate类成员函数实现 #include “Tdate.h” void Tdate:Set(int m,int d,int y) month=m; day=d; year=y; int Tdate:IsLeapYear() return (year%4=0 ,例7.4 使用对象作为函数的参数,60,/例7.4的应用程序: 7_4.cpp #include using namespace std; #include “Tdate.h“ void someFunc(Tdate someday) someday.Print(); if(someday.IsLeapYear() cout “leap yearn“; else cout “not leap yearn“; void main() Tdate s; s.Set(2,15,2003); someFunc(s); /对象作为函数参数 ,例7.4 使用对象作为函数的参数,61,例7.5:类的定义和例7.4相同。主程序把类对象的指针作为实参数来调用函数。,例7.5 使用对象指针作为函数的参数,62,/例7.5:使用对象指针传递函数参数 #include using namespace std; #include “Tdate.h “ void someFunc(Tdate* pS) /对象的指针作形参 pS-Print(); / ,pS是s对象的指针 if(pS-IsLeapYear() cout “leap yearn“; else cout “not leap yearn“; void main() Tdate s; s.Set(2,15,2003); someFunc( /对象的地址作实参 ,例7.5 使用对象指针作为函数的参数,63,例7.6:类的定义和例7.4相同。主程序把类对象的引用作为实参数来调用函数。,例7.6 使用对象引用作为函数的参数,64,/例7.6:使用对象引用传递函数参数 #include using namespace std; #include “Tdate.h” void someFunc(Tdate ,void main() Tdate s; s.Set(2,15,2003); someFunc(s); ,例7.6 使用对象引用作为函数的参数,65,/例7-7:使用对象的引用作为函数的返回值 #include using namespace std; class Rectangle private: float width,height; public: void SetRectangle(float newW, float newH) width = newW; height=newH; float Area() return width*height; ;,例7.7 使用对象引用作为函数的返回值,66,/例7-7:使用对象的引用作为函数的返回值 Rectangle ,例7.7 使用对象引用作为函数的返回值,67,例7.7 使用对象引用作为函数的参数,7.1 类和对象的定义 7.2 对象的使用 7.3 构造函数 7.4 析构函数 7.5 类的静态成员 7.6 类成员的保护和使用 7.7 运算符重载 7.8 类的组合 7.9 面向对象分析和设计,第7章 类与对象,69,每个对象区别于其他对象的地方主要有两个, 外在的区别就是对象的标识符,即对象的名称, 而内在的区别就是对象自身的属性值,即数据成员的值。 在定义一个对象的时候要给它分配存储空间,也可以同时给它的数据成员赋初值,称为对象的初始化。,7.3 构造函数,70,C+程序中的对象初始化工作由一个特殊的成员函数来完成,就是构造函数。 因为不同类型的对象的初始化工作是不一样的,因此构造函数从属于某个类的,即每个类都要定义它自己的构造函数,它是类的成员函数。,7.3 构造函数,71,定义构造函数的一般形式为: class 类名 public: 类名(形参表); /构造函数的原型 /类的其它成员 ; 类名:类名(形参表) /构造函数的实现 /函数体 ,7.3 构造函数,72,class Clock public: Clock(int H,int M,int S); /构造函数 void SetTime(int newH,int NewM,int newS); void ShowTime(); private: int Hour; int Minute; int Second; ;,7.3 构造函数,73,Clock:Clock(int H,int M,int S) /类的构造函数在类外实现 Hour=H; Minute=M; Second=S; ,构造函数可以在类的内部实现,也可以在类的外部实现,7.3 构造函数,74,class Clock public: Clock(int H,int M,int S) /构造函数 Hour=H; Minute=M; Second=S; void SetTime(int newH,int NewM,int newS); void ShowTime(); private: int Hour; int Minute; int Second; ;,构造函数可以在类的内部实现,也可以在类的外部实现,7.3 构造函数,75,void main() /构造对象MyClock,初始化为8点30分 Clock MyClock(8,30,0); MyClock.ShowTime(); /显示时钟 ,在main函数中,就可以通过Clock类的构造函数来创建和初始化对象,7.3 构造函数,76,构造函数的特点是: 构造函数的函数名与类名相同;而且没有返回值。 构造函数一定是公有函数。 作为类的成员函数,构造函数可以直接访问类的所有数据成员。 在类的内部定义的构造函数是内联函数。构造函数可以带默认形参值,也可以重载。,7.3 构造函数,77,在声明类时如果没有定义类的构造函数,编译系统就会在编译时自动生成一个默认形式的构造函数,默认构造函数的形式: 类名:类名() ,7.3 构造函数,78,默认构造函数是构造对象时不提供参数的构造函数。 在以下情况下,系统将调用默认构造函数来构造对象: 直接定义一个对象而没有初始化,如: Clock myclock; 用new动态申请的对象而没有初始化值,如: Clock * pclock = new Clock; 定义一个对象数组,如: student classA30;,7.3 构造函数,79,除了无参数构造函数是默认构造函数外,带有全部默认参数值的构造函数也是默认构造函数。 程序中,不能同时出现无参数构造函数和带有全部默认形参值的构造函数。否则,就会出现编译错误。 如果类定义了带参数的构造函数,这时系统不会再自动生成默认构造函数了,可又需要默认构造函数,如上面所列的三种情况,这时,需要为类另定义一个无参构造函数,出现了构造函数的重载。,7.3 构造函数,80,构造函数的重载 构造函数可以像普通函数一样重载,调用时根据参数的不同,选择其中合适的一个。,7.3 构造函数,81,例7.8:为日期类定义4个构造函数,分别是: 带一个参数,仅初始化日; 带二个参数,初始化月、日; 带三个参数,初始化年、月、日; 不带参数。,7.3 构造函数,82,#include using namespace std; class Tdate public: Tdate(); /第一个构造函数 Tdate(int d); /第二个构造函数 Tdate(int m,int d); /第三个构造函数 Tdate(int m,int d,int y); /第四个构造函数 /其他公共成员 private: int month; int day; int year; ;,构造函数的重载,83,Tdate:Tdate() month=4; day=15; year=1995; cout month “/“ day “/“ year endl; Tdate:Tdate(int d) month=4; day=d; year=1996; cout month “/“ day “/“ year endl; Tdate:Tdate(int m,int d) month=m; day=d; year=1997; cout month “/“ day “/“ year endl;,7.3 构造函数,84,Tdate:Tdate(int m,int d,int y) month=m; day=d; year=y; cout month “/“ day “/“ year endl; void main() Tdate aday; /开始用4种方式构造4个对象 Tdate bday(10); Tdate cday(2,12); Tdate dday(1,2,1998); ,7.3 构造函数,85,复制构造函数用来复制一个对象; 生成一个对象的副本有两种途径: 第一种途径是建立一个新对象,然后通过对象的赋值运算来复制。 另一种途径就是使用复制构造函数。 例如: Clock ca(12, 5, 0); /先创建一个对象 Clock cb=ca; /用赋值运算将ca复制到cb; Clock cc(ca); /用复制构造函数将ca复制到cc;,7.3 构造函数,86,图7.6 Clock对象ca复制为cb的内存示意图,7.3 构造函数,87,复制构造函数是形参是本类对象的引用的构造函数。 定义一个复制构造函数的一般形式为: class 类名 public: 类名(类名 类名:类名(类名& 对象名) /函数体 ,7.3 构造函数,88,class Location public: Location(int xx=0,int yy=0)X=xx; Y=yy; Location(Location ,7.3 构造函数,89,复制构造函数 是一种特殊的构造函数,其形参为本类的对象引用。 作用 用一个已有确定值的对象(复制构造函数的形参所指的对象)去初始化一个新建的同类对象。 Location pos1(10,20); Location pos2(pos1); 实现同类对象间的数据传递。 pos2=pos1; 实质是将对象的复制工作用一个函数来完成。 如果要完成复制任务, pos2.X=pos1.x; pos2.Y=pos1.Y; 类外不行;这样的访问只能由类的成员函数实现-复制构造函数.,7.3 构造函数,90,缺省复制构造函数 如果用户未显式地定义类的复制构造函数,则系统会自动生成一个默认的复制构造函数,把成员值一一复制 通过赋值运算符初始化对象时,系统会自动调用复制构造函数。 复制构造函数与原来的构造函数实现了函数的重载。,7.3 构造函数,91,以下三种情况系统会自动调用复制构造函数: 当用类的一个对象去初始化该类的另一个对象时; 如果函数的形参是类的对象,调用函数时,用实参的值初始化形参时; 如果函数的返回值是类的对象,函数执行完成返回调用者时。,7.3 构造函数,92,当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现复制赋值。例: int main(void) Location A(1,2); Location B(A); /复制构造函数被调用 coutB.GetX()endl; return 0; ,7.3 构造函数,93,若函数的形参为类对象,调用函数时,用实参初始化形参,系统自动调用复制构造函数。例如: void f(Location p) coutp.GetX()endl; /调用析构函数 int main() Location A(1,2); f(A); /调用复制构造函数 return 0; ,7.3 构造函数,94,当函数的返回值是类对象时,系统自动调用复制贝构造函数。例如: Location g() Location A(1,2); return A; /调用复制构造函数 int main() Location B; B=g(); return 0; ,7.3 构造函数,7.1 类和对象的定义 7.2 对象的使用 7.3 构造函数 7.4 析构函数 7.5 类的静态成员 7.6 类成员的保护和使用 7.7 运算符重载 7.8 类的组合 7.9 面向对象分析和设计,第7章 类与对象,96,与构造函数相反,当对象生存期结束时,需要调用析构函数,释放对象所占的内存空间。 与构造函数一样,析构函数也是类的一个公有成员函数,它的名称是在类名前加“”构成,没有返回值,和构造函数不同的是析构函数不接受任何参数。 析构函数声明的格式是: 类名();,7.4 析构函数,97,如果程序中不定义析构函数,系统也会提供一个默认的析构函数: 类名() 这个析构函数只能用来释放对象的数据成员所占用的空间,但不包括堆内存空间。 析构函数是在对象生存期即将结束的时刻由系统自动调用的。 类的析构函数不能重载。,7.4 析构函数,98,7.4 析构函数,例7.10:定义学生类student,其中“姓名”用字符指针(char *)来保存,在构造一个学生时,从堆中为“姓名”分配存储空间,那么需要定义析构函数,在对象生存期结束时,把堆空间释放,还给系统。这种情况下,不能使用默认的析构函数。,99,#include using namespace std; class student public: student(int, char*, int, float); /构造函数 student(student,7.4 析构函数,100,student:student(int i, char* c, int a, float s) /构造函数 cout“Constructing.“endl; id = i; age = a; score = s; name = new charstrlen(c)+1; if (name != 0) strcpy(name, c); student:student(student /复制字符串 ,7.4 析构函数,101,student:student() /析构函数 cout“Destructing.“endl; if(name!=NULL) delete name; void student:printstu() cout“学号:”id“ 姓名:“name; cout“年龄:“age“成绩:“scoreendl; void main() student stu(1,“wang“,18, 86); / student stu2(stu); stu.printstu(); ,7.4 析构函数,7.1 类和对象的定义 7.2 对象的使用 7.3 构造函数 7.4 析构函数 7.5 类的静态成员 7.6 类成员的保护和使用 7.7 运算符重载 7.8 类的组合 7.9 面向对象分析和设计,第7章 类与对象,103,静态成员是类的特殊成员,采用static关键字来声明。分为: 静态数据成员 静态成员函数,7.5 静态成员,104,静态数据成员是类的数据成员的一种特例,采用static关键字来声明。 class Student public: Student(char* pName =“no name“); Student(); void PrintC() cout“The number of students is “countendl; private: static int count; /若写成count=0;则非法 char name20; ;,1.静态数据成员,105,类的数据成员在类的每一个对象中分别存储不同的数值,但是静态数据成员则不同,它在整个类中只有一个拷贝,由该类的所有对象共同维护和使用,从而实现了同一类的不同对象之间的数据共享。 Student a(“sun”),b(“li”),c(“liu”);,1.静态数据成员,106,静态数据成员具有静态生存期。 在类的声明中只能声明静态数据成员的存在。 由于类的声明是抽象的,静态数据成员的初始化需要在类的外部进行,通过类名对它进行访问。 类名:标识符 例:int Student:count =0;,1.静态数据成员,107,例7.11:定义学生类,定义一个静态数据成员count,用来统计学生的人数。,1.静态数据成员,108,/例7.11:静态数据成员的定义和使用 #include #include using namespace std; class Student public: Student(char* pName =“no name“); Student(); void PrintC() cout“The number of students is “countendl; private: static int count; /若写成count=0;则非法 char name20; ;,1.静态数据成员,109,Student:Student(char* pName) cout “create one studentn“; strncpy(name, pName,20); name19=0; count+; /静态成员:每创建一个对象,学生人数增1 Student:Student() cout “destruct one studentn“; count-; /每析构一个对象,学生人数减1 cout“The number of students is “countendl; ,1.静态数据成员,110,int Student:count =0; /静态数据成员在类外分配空间和初始化 void main() Student s1; s1.PrintC(); Student s2; s2.PrintC(); ,1.静态数据成员,111,可以通过定义和使用静态成员函数来访问静态数据成员。 所谓静态成员函数就是使用static关键字声明函数成员。 同静态数据成员一样,静态成员函数也属整个类,由同一个类的所有对象共同维护,为这些对象所共享。,2.静态成员函数,112,静态成员函数作为成员函数,它的访问属性可以受到类的严格控制。 对公有静态成员函数,可以通过类名或对象名来调用; 而一般的非静态公有成员函数只能通过对象名来调用。 静态成员函数可以直接访问该类的静态数据成员和成员函数;而访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问。,2.静态成员函数,113,可以将例7.11中的PrintC函数定义为静态成员函数: static void PrintC() cout“The number of students is “countendl; ,2.静态成员函数,114,在main函数中,就可以在创建任何对象前,访
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 放射性矿石磁选分离工艺考核试卷及答案
- 海洋水文气象观测员晋升考核试卷及答案
- D供应商分类标准及注册评价等测试卷附答案
- 银行招聘文秘试题及答案
- 银行行长考核试题及答案
- 中职专业试题及答案
- 电力专业试题及答案
- 茶学专业试题及答案
- 中药鉴定专业试题及答案
- 专业美术知识试题及答案
- 餐饮咨询顾问合同范本
- 四级专项模拟考试题库及答案
- 川教版(2024)七年级上册信息科技全册教案
- 2025-2026学年新疆师范大学附属实验高中高三数学第一学期期末统考试题
- 深圳中考英语听说考试模仿朗读技巧点拨
- 电子商务法律法规及合规性要求
- 2025年人教版小学五年级数学下册期末考试卷(附参考答案和解析)
- 2025年第九届“学宪法、讲宪法”知识竞赛题库及答案(中小学组)
- 部编人教版小学语文六年级上册【课内外阅读理解专项训练(完整)】含答案
- 2025年高考陕晋宁青卷地理试题解读及答案讲评(课件)
- 3.1生活在新型民主国家 教案 -2025-2026学年统编版道德与法治九年级上册
评论
0/150
提交评论