【文档说明】C--高级语言程序设计-第七章-类与对象汇总课件.ppt,共(100)页,355.501 KB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44440.html
以下为本文档部分文字说明:
C++高级语言程序设计第7章类与对象北京邮电大学信息与通信工程学院2022/11/24北京邮电大学信息与通信工程学院-2-类是实现C++面向对象程序设计的基础。面向对象程序设计的基本特点有:抽象、封装、继承
和多态,类把数据和函数封装在一起,是C++封装的基本单元。2022/11/24北京邮电大学信息与通信工程学院-3-7.1类和对象的定义7.2对象的使用7.3构造函数7.4析构函数7.5类的静态成员7.6类成员的保护和使用7.7运算符重载
7.8类的组合7.9应用举例7.10面向对象分析和设计第7章类与对象7.1类和对象的定义2022/11/24北京邮电大学信息与通信工程学院-5-7.1类和对象的定义一个类表示现实生活中的一类事物,比如“学生”,事物有相应的特征或属性,它们就是类的数据成员;事物可能有行为动作,也可能被某
些行为动作所操作,这些都用函数来实现,这些函数和类有着不可分割的关系,是构成类的函数成员,或者叫成员函数。在C++中,类实际上相当于一种用户自定义的数据类型。2022/11/24北京邮电大学信息与通信工程学院-6-对
象是一类事物中的一个具体的个体。在定义了类类型后,就可以定义该类型的变量,这个变量就称为类的对象(或实例)。所以,从程序设计的角度来看,对象就相当于变量。7.1类和对象的定义2022/11/24北京邮电大学信息与通信工程学院-7-举例:classStudent//类的定义{private:inti
d;char[20]name;intage;floatscore;public:voidgetscore()voidprintstu()};7.1类和对象的定义2022/11/24北京邮电大学信息与通信工程学
院-8-1、使用类对象如果已经知道某个类的功能和接口函数,就可以使用它了。先定义类对象,通过对象调用接口函数实现一定的功能。classStudentstu01;//class也可以省略不写stu01.getscore();stu01.printstu();这个过程的本质是:根
据对象所需要完成的任务,向对象发送消息。对象收到消息后,调用接口中的相应的函数,完成它的功能。对象只需要知道“做什么”,具体工作由成员函数来完成。2022/11/24北京邮电大学信息与通信工程学院-9
-2、类的声明类的声明具体说明类的组成,声明类的语法形式为:class类名称{public:公有成员protect:保护型成员private:私有成员};2022/11/24北京邮电大学信息与通信工程学院-10-其中,“成员”既可以是数据成员,
也可以是成员函数的原型。数据成员的声明方式与一般变量相同。函数成员是描述类的对象可以进行的操作,一般在类中声明原型,在类声明的外面定义函数的具体实现。关键字public、protect、private说明类成员的访问控制属性。私有(private)成员只允许本类的成员函数来访问;公有(p
ublic)成员是类对外的接口,在类声明和类(函数)实现之后,类的对象可以访问公有成员。保护型(protected)成员的可访问性和私有成员的性质相似。2、类的声明2022/11/24北京邮电大学信息与通信工程学院-11-关于访问控制属性,注意:在类声明中,
三种访问控制属性,可以按任意次序出现,也可以不出现。public等关键字也可以多次出现,但是一个成员只能具有一种访问控制属性。如果不写访问控制属性关键字,默认的是private。在书写时通常习惯将公有类型放在最前面,这样便于阅读,因为它们是外部访问时所要了解的。一般情况下,一个类的数据成员应该声明
为私有成员,这样封装性较好。一个类应该有一些公有的函数成员,作为对外的接口,否则别的代码无法访问类2、类的声明2022/11/24北京邮电大学信息与通信工程学院-12-类的成员函数描述的是类的行为或操作
。函数的原型声明要在类的主体中,原型说明了函数的参数表和返回值类型。而函数的具体实现一般是写在类声明之外的。在类的外部定义成员函数的语法形式为:返回值类型类名::成员函数名(参数表){函数体}3、类的成员函数2022/11/24北京邮电大学信息与通信工程学院-13-如果在类的内部定
义成员函数的具体实现,则该成员函数为内联成员函数。函数定义时没有任何的附加说明,所以称为隐式声明的内联成员。3、类的成员函数2022/11/24北京邮电大学信息与通信工程学院-14-定义一个对象和定义一个一般变量相同。定义变量时要分配存储空间,同样
,定义一个对象时要分配存储空间,一个对象所占的内存空间是类的数据成员所占的空间总和。类的成员函数存放在代码区,不占内存空间。类的成员是抽象的,对象的成员才是具体的。类的数据成员都不会有具体的属性值。只
有对象的成员才会有具体的属性值。4、对象2022/11/24北京邮电大学信息与通信工程学院-15-声明了类及其对象,在类的外部(指类定义和成员函数的实现代码之外),就可以访问对象的公有成员(包括数据成员和函数成员)了。在类的外部,只能通过对象访问类的公有成员;在类的
成员函数内部,可以直接访问类的所有成员,这就实现了对访问范围的有效控制。4、对象2022/11/24北京邮电大学信息与通信工程学院-16-类作用域是指类定义和相应的成员函数定义的范围,通俗地称为类的内部。C++
认为一个类的全部成员都是一个整体的相关部分。一个类的所有成员位于这个类的作用域内,在该范围内,一个类的成员函数对本类的其它成员具有无限制的访问权。5、类的作用域与可见性2022/11/24北京邮电大学信息与
通信工程学院-17-要声明一个时钟类,任何一个时钟都应该有时、分、秒的值,这就是时钟的属性特征;时钟的操作应该有设置时间、显示时间等。6、时钟类举例2022/11/24北京邮电大学信息与通信工程学院-18-//声明时钟类的头文件:Clo
ck.h#include<iostream>usingnamespacestd;classClock//类的声明{public:voidSetTime(intnewH=0,intnewM=0,intnewS=0);vo
idShowTime();voidShowTime(intn);private:intHour;intMinute;intSecond;};6、时钟类举例2022/11/24北京邮电大学信息与通信工程学院-19-//实现类成员函数的源文件:Cl
ock.cpp#include"Clock.h"voidClock::SetTime(intnewH,intnewM,intnewS)//SetTime()函数定义{Hour=newH;Minute=newM;Second=newS;}voidClock::ShowTime()//ShowTime
()函数定义{cout<<Hour<<":"<<Minute<<":"<<Second<<endl;}voidClock::ShowTime(intn)//重载函数的定义{cout<<Hour<<"点"<<Minute<<"分"<<Second<<"秒"<<endl;}6
、时钟类举例2022/11/24北京邮电大学信息与通信工程学院-20-//测试应用程序:7-1.cpp#include"Clock.h"voidmain(){Clockmyclock;//类的对象myclock.SetTime(12,5,0);//设置时间myclock.ShowTim
e();//第一种方式显示时间myclock.ShowTime(1);//第二种方式显示时间}6、时钟类举例7.2对象的使用2022/11/24北京邮电大学信息与通信工程学院-22-7.2对象的使用对象是类的一个具体的实例,类和对象的关系相当于普遍与特殊的关系。在C++中,类是一个自
定义的数据类型,对象是该数据类型的一个变量。所以,可以定义一个全局的对象,也可以在函数体中定义一个局部的对象,或者动态地从堆中申请空间来创建一个对象,还可以定义对象数组,以及使用对象作为函数的参数与返回值。2022/11/24北京邮电大学信息与通
信工程学院-23-1、对象指针声明对象指针的一般语法形式为:类名*对象指针名;使用对象指针访问对象的成员,语法形式为:对象指针名->公有成员;例如:Clockc;//在栈中分配Clock型存储空间Clock*pc1=newClock;//在堆中分
配Clock型存储空间Clock*pc2=&c;pc1->SetTime(12,5,0);2022/11/24北京邮电大学信息与通信工程学院-24-1、对象指针//使用对象指针和堆对象对例7-1中的主函数进行修改voidmai
n(){Clock*pmyclock=newClock;pmyclock->SetTime(12,5,0);pmyclock->ShowTime();deletepmyclock;}2022/11/24北京邮电大学信息与通信工程学院-25-2、this指针问:一个类中所有对象调用的成员函数都执
行同一段代码。那么,成员函数又是怎么识别当前是那个对象在访问呢?答:this指针指出了成员函数当前所操作的数据所属的对象。不同的对象调用成员函数时,this指针将指向不同的对象,也就可以访问不同对象的数据成员。2022/11/24北京邮电大学信息与通信工程学院-26-3、
对象数组对象数组的元素是对象,不仅具有数据成员,而且还有函数成员,可以通过数组元素调用成员函数。2022/11/24北京邮电大学信息与通信工程学院-27-3、对象数组//例7-3使用对象数组#include<iostream>
#include<iomanip>#include<string>usingnamespacestd;classstudent{private:intid;stringname;intage;floatscore;public:voidset(int,char*,int
,float);voidprintstu(){cout<<"学号:"<<id<<"姓名:"<<setw(5)<<name;cout<<"年龄:"<<age<<"成绩:"<<score<<endl;}};//student类声明结束2022/11/2
4北京邮电大学信息与通信工程学院-28-3、对象数组voidstudent::set(inti,char*c,inta,floats){id=i;name=c;age=a;score=s;}voidmain(){studentstu[5
];//对象数组stu[0].set(1,"wang",18,86);//设置数组中每个对象stu[1].set(2,"Li",18,72);stu[2].set(3,"zhao",18,80);stu[3].set(4,"guo
",18,85);stu[4].set(5,"meng",18,75);for(inti=0;i<5;i++)stu[i].printstu();//显示每个对象}2022/11/24北京邮电大学信息与通信工程学院-29-4、对象用做函
数的参数和返回值可以将对象作为参数传递给一个函数或从函数返回一个对象。直接用对象作为参数,调用函数时,进行值传递,实参的值要复制给形参,如果类的数据成员较多时,需要一一复制,这种参数传递方式效率不高,可以使用对象指针或
对象引用方式来传递函数参数。2022/11/24北京邮电大学信息与通信工程学院-30-4、对象用做函数的参数和返回值//例7-4:使用对象传递函数参数//Tdate.h:Tdate类声明#include<i
ostream>usingnamespacestd;classTdate{public:voidSet(int,int,int);//成员函数声明intIsLeapYear();voidPrint();private:intmonth
;intday;intyear;};2022/11/24北京邮电大学信息与通信工程学院-31-4、对象用做函数的参数和返回值//例7-4:使用对象传递函数参数//Tdate.cpp:Tdate类成员函数实现#include"Tda
te.h"voidTdate::Set(intm,intd,inty){month=m;day=d;year=y;}intTdate::IsLeapYear(){return(year%4==0&&year%100!=0)
||(year%400==0);}voidTdate::Print(){cout<<month<<"/"<<day<<"/"<<year<<endl;}2022/11/24北京邮电大学信息与通信工程学院-32-4、对象用做函数的参数
和返回值//例7-4:使用对象传递函数参数//例7-4的应用程序:7-4.cpp#include<iostream>usingnamespacestd;#include"Tdate.h"voidsomeFunc(Tdatesomeday)//普通
函数的参数是一个类对象{someday.Print();if(someday.IsLeapYear())cout<<"leapyear\n";elsecout<<"notleapyear\n";}voidmain(){Tdates;s.Set(2,15,2003);someFu
nc(s);//对象作为函数参数}2022/11/24北京邮电大学信息与通信工程学院-33-4、对象用做函数的参数和返回值//例7-5:使用对象指针传递函数参数//例7-5的应用程序:7-5.cpp#include<iostream>usingnamespacestd;#
include"Tdate.h"//包含Tdate.h头文件voidsomeFunc(Tdate*pS)//对象指针作为函数形参{pS->Print();//pS是s对象的指针if(pS->IsLeapYear())cout<<"leapyear\n";elsec
out<<"notleapyear\n";}voidmain(){Tdates;s.Set(2,15,2003);someFunc(&s);//对象的地址作为实参}2022/11/24北京邮电大学信息与通信工程学院-34-4、
对象用做函数的参数和返回值//例7-7:使用对象的引用作为函数的返回值#include<iostream>usingnamespacestd;classRectangle{private:floatwidth,h
eight;public:voidSetRectangle(floatnewW,floatnewH){width=newW;height=newH;}floatArea(){returnwidth*height;}};2022/11/24北京邮电大学信息与通信工程学院
-35-4、对象用做函数的参数和返回值//例7-7:使用对象的引用作为函数的返回值Rectangle&compare(Rectangle&r1,Rectangle&r2){if(r1.Area()>r2.Area())returnr1;els
ereturnr2;}voidmain(){Rectanglerect1,rect2,rect3;rect1.SetRectangle(12,21);rect2.SetRectangle(21,14);rect3.SetRectangle(21,12);Rectangle&maxR=co
mpare(rect3,compare(rect1,rect2));cout<<"Thelargerrectanglehasarea:"<<maxR.Area()<<endl;}7.3构造函数2022/11/24北京邮电大学信息与通信工程学院-37-7.3构造函
数每个对象区别于其他对象的地方主要有两个,外在的区别就是对象的标识符,即对象的名称,而内在的区别就是对象自身的属性值,即数据成员的值。在定义一个对象的时候要给它分配存储空间,也可以同时给它的数据成员赋初值,称为对象的初始化。C++程序中的对象初始化工作由
一个特殊的成员函数来完成,就是构造函数。因为不同类型的对象的初始化工作是不一样的,因此构造函数从属于某个类的,即每个类都要定义它自己的构造函数,它是类的成员函数。2022/11/24北京邮电大学信息与通信工程学院-38
-定义构造函数的一般形式为:class类名{public:类名(形参表);//构造函数的原型//类的其它成员};类名::类名(形参表)//构造函数的实现{//函数体}7.3构造函数2022/11/24北京邮电
大学信息与通信工程学院-39-构造函数的特点是:构造函数的函数名与类名相同;而且没有返回值。构造函数一定是公有函数。作为类的成员函数,构造函数可以直接访问类的所有数据成员。在类的内部定义的构造函数是内联函数。构造函数可
以带默认形参值,也可以重载。7.3构造函数2022/11/24北京邮电大学信息与通信工程学院-40-在声明类是如果没有定义类的构造函数,编译系统就会在编译时自动生成一个默认形式的构造函数,默认构造函数是构造对象时不提供参数的构造函数。除了无参
数构造函数是默认构造函数外,带有全部默认参数值的构造函数也是默认构造函数。7.3构造函数2022/11/24北京邮电大学信息与通信工程学院-41-//例7-8:构造函数的重载#include<iostream>usingnamespacest
d;classTdate{public:Tdate();//第一个构造函数Tdate(intd);//第二个构造函数Tdate(intm,intd);//第三个构造函数Tdate(intm,intd,inty);//第
四个构造函数//其他公共成员private:intmonth;intday;intyear;};7.3构造函数2022/11/24北京邮电大学信息与通信工程学院-42-//例7-8:构造函数的重载Tdate::Tdate(){month=4;day=15;year=1
995;cout<<month<<"/"<<day<<"/"<<year<<endl;}Tdate::Tdate(intd){month=4;day=d;year=1996;cout<<month<<"
/"<<day<<"/"<<year<<endl;}Tdate::Tdate(intm,intd){month=m;day=d;year=1997;cout<<month<<"/"<<day<<"/"<<y
ear<<endl;}Tdate::Tdate(intm,intd,inty){month=m;day=d;year=y;cout<<month<<"/"<<day<<"/"<<year<<endl;}7.3构
造函数2022/11/24北京邮电大学信息与通信工程学院-43-//例7-8:构造函数的重载voidmain(){Tdateaday;//开始用4种方式构造4个对象Tdatebday(10);Tdatecda
y(2,12);Tdatedday(1,2,1998);}7.3构造函数2022/11/24北京邮电大学信息与通信工程学院-44-复制构造函数就是函数的形参是类的对象的引用的构造函数。通过等于号复制对象时,系统会自动调用复
制构造函数。复制构造函数与原来的构造函数实现了函数的重载。如果程序在类定义时没有显式定义复制构造函数,系统也会自动生成一个默认的复制构造函数,把成员值一一复制。某些情况下必须显式地定义一个复制构造函数。例如,如果类的数据成员包括指针变量,
类的构造函数用new运算符为这个指针动态申请空间。7.3构造函数2022/11/24北京邮电大学信息与通信工程学院-45-以下三种情况系统会自动调用复制构造函数:当用类的一个对象去初始化该类的另一个对象时如果函数的形参是类的对象,调用函数时,进行形参和实参结合时
如果函数的返回值是类的对象,函数执行完成返回调用者时7.3构造函数7.4析构函数2022/11/24北京邮电大学信息与通信工程学院-47-与构造函数相反,当对象生存期结束时,需要调用析构函数,释放对象所占的内存空间。与构造函数一样,析构函数也是类的一个公有成员函数,它的名称是在类名
前加“~”构成,没有返回值,和构造函数不同的是析构函数不接受任何参数。析构函数是在对象生存期即将结束的时刻由系统自动调用的。如果程序员没有定义析构函数,系统将自动生成和调用一个默认析构函数。类的析构函数不能重载。7
.4析构函数2022/11/24北京邮电大学信息与通信工程学院-48-//例7-10:用户必须自己定义析构函数的示例#include<iostream>usingnamespacestd;classstudent{public:student(int,ch
ar*,int,float);student(student&);~student();voidprintstu();private:intid;char*name;intage;floatscore;};7.4析构函数2022/11/24北京邮电大学信息与通信工程学院-49-student:
:student(inti,char*c,inta,floats){cout<<"Constructing..."<<endl;id=i;age=a;score=s;name=newchar[strlen(c)+1];if(name!=0)strcpy(name,c
);}student::student(student&s)//复制构造函数{cout<<"CopyConstructing..."<<endl;id=s.id;//一般成员简单复制age=s.age;score=s.score;na
me=newchar[strlen(s.name)+1];//先申请堆空间if(name!=0)strcpy(name,s.name);//复制字符串}7.4析构函数2022/11/24北京邮电大学信息与通信工程学院-50-//例7-
10:用户必须自己定义析构函数的示例student::~student(){cout<<"Destructing..."<<endl;delete[]name;name=0;}voidstudent::printstu(){cout<<"学号:"<<id<<"姓名:"<<name;cout<<"年
龄:"<<age<<"成绩:"<<score<<endl;}voidmain(){studentstu(1,"wang",18,86);stu.printstu();}7.4析构函数7.5类的静态成员20
22/11/24北京邮电大学信息与通信工程学院-52-1、静态数据成员静态数据成员是类的数据成员的一种特例,采用static关键字来声明。类的数据成员在类的每一个对象中分别存储不同的数值,但是静态数据
成员则不同,它在整个类中只有一个拷贝,由该类的所有对象共同维护和使用,从而实现了同一类的不同对象之间的数据共享。2022/11/24北京邮电大学信息与通信工程学院-53-1、静态数据成员静态数据成员具有静态生存期。在
类的声明中只能声明静态数据成员的存在。由于类的声明是抽象的,静态数据成员的初始化需要在类的外部进行,通过类名对它进行访问。2022/11/24北京邮电大学信息与通信工程学院-54-2、静态成员函数可以通过定义和使用
静态成员函数来访问静态数据成员。所谓静态成员函数就是使用static关键字声明函数成员。同静态数据成员一样,静态成员函数也属整个类,由同一个类的所有对象共同维护,为这些对象所共享。2022/11/24北京邮电大学信息与通信工程学院-55-2、静态成员函数静态成员函数作为成员函数,它的访问属性可
以受到类的严格控制。对公有静态成员函数,可以通过类名或对象名来调用;而一般的非静态公有成员函数只能通过对象名来调用。静态成员函数可以直接访问该类的静态数据成员和函数成员;而访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访
问。2022/11/24北京邮电大学信息与通信工程学院-56-//例7-11:静态数据成员的定义和使用#include<iostream>#include<string>usingnamespacestd;classStudent{public:Student(char*pName="non
ame");~Student();staticvoidPrintC(){cout<<"Thenumberofstudentsis"<<count<<endl;}private:staticintcount;//若写成count=0,则非法stri
ngname;};7.5类的静态成员2022/11/24北京邮电大学信息与通信工程学院-57-Student::Student(char*pName)//="noname"){cout<<"createonestudent\n";name=pName;count++
;//静态成员:每创建一个对象,学生人数增1}Student::~Student(){cout<<"destructonestudent\n";count--;//每析构一个对象,学生人数减1cout<<"Thenumberofstudentsis"<<count<<
endl;}intStudent::count=0;//静态数据成员在类外分配空间和初始化,static不用写voidmain(){Student::PrintC();//通过类名调用静态成员函数St
udents1;s1.PrintC();Students2;s2.PrintC();}7.5类的静态成员7.6类成员的保护和使用2022/11/24北京邮电大学信息与通信工程学院-59-1、类的封装在程序设计中,将
数据与操作数据的行为进行有机地结合,这就是封装。C++语言提供类这种语言成分来实现封装,类是属性和操作的结合体,并且在定义类的属性和操作时,规定了它们的可见性。通过封装将一部分成员作为类与外部的接口,而将其它的成员隐藏起来,以防外界
的干扰和误操作,使程序的不同模块之间的相互影响减小到最低限度。2022/11/24北京邮电大学信息与通信工程学院-60-2、友元在一个类中,可以利用关键字friend将别的模块(一般函数、其它类的成员函数或其它类)声明为本类的友元,这样类中本来隐藏的信息(私有和保护成员)就可以被友元访问
。友元提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。友元并不是类的成员。2022/11/24北京邮电大学信息与通信工程学院-61-2、友元关于友元类,要注意:友元关系是不能传递的。B类是A类的友元,C类是B类的友元,C类和A类之间,如果没有声明,就没有
任何友元关系,不能进行数据共享。友元关系是单向的。如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据。2022/11/24北京邮电大学信息与通信工程学院-62-//例7-12:使用友
元函数计算两点距离#include<iostream>#include<cmath>usingnamespacestd;classPoint//Point类定义{public://外部接口Point(intxx=0,int
yy=0){X=xx;Y=yy;}intGetX(){returnX;}intGetY(){returnY;}friendfloatfDist(Point&a,Point&b);//友元函数声明private://私有数据成员intX,Y;};7.6类成员的保护和使用
2022/11/24北京邮电大学信息与通信工程学院-63-//例7-12:使用友元函数计算两点距离floatfDist(Point&p1,Point&p2)//友元函数实现{doublex=double(p1.X-p2.X);//通过对象访问私有数据成员doubley=doub
le(p1.Y-p2.Y);returnfloat(sqrt(x*x+y*y));}voidmain()//主函数{Pointmyp1(1,1),myp2(4,5);//定义Point类的对象cout<<"Thedistanceis:";cout<<fDist(myp1,myp2)<<
endl;//计算两点间的距离}7.6类成员的保护和使用2022/11/24北京邮电大学信息与通信工程学院-64-//例7-13:友元类的使用#include<iostream>usingnamespacestd;classStudent;//前向引用声明,
只声明类名,类定义在后面classTeacher{public:Teacher(inti,char*c);voidshow();voidassignGrades(Student&s);//使用未定义的类,需要前向引用声明private:char*n
ame;intid;};classStudent{public:Student(inti,char*c,floats,Teacher*t);voidprintstu();friendclassTeacher;private:Teacher*pT;intsid;char*name;floatgra
de;};7.6类成员的保护和使用2022/11/24北京邮电大学信息与通信工程学院-65-Student::Student(inti,char*c,floats,Teacher*t){sid=i;name=newchar[strlen(c)+1
];if(name!=0)strcpy(name,c);grade=s;pT=t;}voidStudent::printstu(){cout<<"学号:"<<sid<<"姓名:"<<name;cout<<"成绩:"<<grade<<endl;}Teacher
::Teacher(inti,char*c){id=i;name=newchar[strlen(c)+1];if(name!=0)strcpy(name,c);}7.6类成员的保护和使用2022/11/24北京邮电大学信息与通信工程学院-66-voidTeache
r::show(){cout<<"工作证号:"<<id<<"姓名:"<<name<<endl;}voidTeacher::assignGrades(Student&s){if(s.pT->id==id)s.grade=4.0;//修改学生成绩,直接操作
另一个类的保护成员}voidmain(){Teacherwang(62,"wangyi");wang.show();Students1(10,"zhangsan",87.6,&wang);s1.printstu();wang.assignGrade
s(s1);s1.printstu();Students2(12,"lisi",80,&wang);s2.printstu();wang.assignGrades(s2);s2.printstu();}7.6类成员的保护和使用2022/11/24北京邮电大学信息与通信
工程学院-67-3、常对象和常成员定义对象时用const进行修饰,称为常对象,它的数据成员值在对象的整个生存期间内不能被改变。也就是说,常对象在定义时必须进行初始化,而且不能被更新。使用常量,既实现了数据共享、又可以保证数据不会被改变。2022/11/24北京邮电大学信息与通信工程学院
-68-3、常对象和常成员对于类的某个成员函数,使用const关键字修饰,称为常成员函数。常对象只能调用常成员函数,保证常对象的数据成员不能被修改。使用const说明的数据成员称为常数据成员。如果在一个类中说明了常数据成员,那么任何函数中都不能对该成员赋值。构造函数对该数
据成员进行初始化,就只能通过初始化列表。2022/11/24北京邮电大学信息与通信工程学院-69-3、常对象和常成员常成员函数的特点:const是函数类型的一个组成部分,在函数实现时也要带const关键字。常成员函数不能更新对象的数据成员,也不能调用该类中的非常成员
函数。常对象只能调用常成员函数,但是常成员函数也可以被普通对象来调用。const关键字可以被用于参与对重载函数的区分。2022/11/24北京邮电大学信息与通信工程学院-70-//例7-14:常成员函数和常对象示例#include<iostream>usingnamespace
std;classR{public:R(intr1,intr2){R1=r1;R2=r2;}voidchange(int,int);voidprint()const;private:intR1,R2;};7.6类成员的保护和使用2022/11/24
北京邮电大学信息与通信工程学院-71-//例7-14:常成员函数和常对象示例voidR::change(inta,intb){R1=a;R2=b;}voidR::print()const{cout<<R1<<";"<<R2
<<endl;}voidmain(){Ra(5,4);a.print();//也调用voidprint()constconstRb(20,52);b.print();//调用voidprint()const}7.6类成员的
保护和使用2022/11/24北京邮电大学信息与通信工程学院-72-//例7-15:常数据成员使用举例#include<iostream>usingnamespacestd;classA{public:A(inti);voidprint();constint&r;priv
ate:constinta;staticconstintb;//静态常数据成员};constintA::b=10;//静态常数据成员在类外说明和初始化7.6类成员的保护和使用2022/11/24北京邮电大学信息与通信工程学院-73-//
例7-15:常数据成员使用举例A::A(inti):a(i),r(a)//常数据成员只能通过初始化列表来获得初值{/*因为a和r是常数据成员,不能把语句a=i;r=a;写在构造函数体内*/}voidA::print(){cout<<a<<":"<<b<<":"<<r<<endl;}vo
idmain()/*建立对象x和y,并以100和0作为初值分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋初值*/{Ax(100),y(0);x.print();y.print();}7.6类成员的保护和使用7.7运算符重载
2022/11/24北京邮电大学信息与通信工程学院-75-7.7运算符重载运算符重载(OperatorOverloading),使得程序员可以把C++的运算符扩展到自定义类型和类类型的领域。使用运算符重载可以使函数调用更方便。运算符重载的实质是函数重载。只不过它重载的是类似“+-*
/=“这样的操作符。2022/11/24北京邮电大学电信工程学院计算机技术中心-76-例子:#include<iostream>usingnamespacestd;voidmain(){chars1[20]=”H
ello”;chars2[20]=”world”;chars3[20];strcpy(s3,s1);//字符串拷贝cout<<s3<<endl;strcat(s3,s2);//字符串连接cout<<s3<<endl;}2022/11/24北京邮电大学电信工程学院
计算机技术中心-77-例子:添加运算符重载#include<string>#include<iostream>usingnamespacestd;voidmain(){strings1="Hello";strings2="worl
d";strings3;s3=s1;//字符串拷贝cout<<s3<<endl;s3=s1+s2;//字符串连接cout<<s3<<endl;}2022/11/24北京邮电大学信息与通信工程学院-78-7.7运算符重载运算符重载需要遵循一定的规则:重载运算符时,运算符的运
算顺序和优先级不变,操作数个数不变。不能创造新的运算符,只能重载C++中已有的运算符。有6个运算符不能重载。OperatorName.类属关系运算符.*成员指针运算符::作用域运算符?:条件运算符#编译预处理符号size
of()取数据类型的长度2022/11/24北京邮电大学信息与通信工程学院-79-7.7运算符重载重载为类的成员函数,其形式为:函数类型operator运算符(形参表){函数体;}重载为类的友元函数,其形式
为:friend函数类型operator运算符(形参表){函数体;}2022/11/24北京邮电大学信息与通信工程学院-80-//例7-17:在复数类中重载+、−、+=运算符#include<iostream>#include<iomanip>usingnamespac
estd;classcomplex{public:complex(doublereal=0,doubleimag=0):r(real),i(imag){}complexoperator+(complex&);//重载运
算符的函数原型complexoperator-(complex&);complexoperator+=(complex&);voidprint(){cout<<setiosflags(ios::showpos)<<r<<
""<<i<<'i'<<endl;}private:doubler,i;};7.7运算符重载2022/11/24北京邮电大学信息与通信工程学院-81-//例7-17:在复数类中重载+、−、+=运算符complexcomplex::operator+(complex&c)//重载“
+”运算符{returncomplex(r+c.r,i+c.i);}complexcomplex::operator-(complex&c)//重载“-”运算符{returncomplex(r-c.r,i-c.i);}complexcompl
ex::operator+=(complex&c)//重载“+=”运算符{r+=c.r;i+=c.i;return*this;}7.7运算符重载2022/11/24北京邮电大学信息与通信工程学院-82-//例7-17:在复数类中重载+、−、+=运算符voidmain(){complexc1(
1,1),c2(3,3),c3;c3=c1+c2;//复数相加c3.print();c3=c1-c2;//复数相减c3.print();c3+=c2+=c1;//复数相加后赋值c3.print();}7.7运算符重载2022/11/24北京邮电大学信息与通信
工程学院-83-//例7-18用友元函数重载复数类的+、−、+=运算符#include<iostream>#include<iomanip>usingnamespacestd;classcomplex{public:complex(doublereal=0,do
ubleimag=0):r(real),i(imag){}friendcomplexoperator+(complex&,complex&);friendcomplexoperator-(complex&,complex&);friendcomplex
&operator+=(complex&,complex&);voidprint(){cout<<setiosflags(ios::showpos)<<r<<""<<i<<'i'<<endl;}private:doubler,i;};7.7运算符重载2022/11/24北京邮电大学信
息与通信工程学院-84-//例7-18用友元函数重载复数类的+、−、+=运算符complexoperator+(complex&c1,complex&c2)//重载“+”运算符{returncomplex(c1
.r+c2.r,c1.i+c2.i);}complexoperator-(complex&c1,complex&c2)//重载“-”运算符{returncomplex(c1.r-c2.r,c1.i-c2.i);}complex&operator+=(complex&c1,complex&c2)/
/重载“+=”运算符{c1.r+=c2.r;c1.i+=c2.i;returnc1;}7.7运算符重载2022/11/24北京邮电大学信息与通信工程学院-85-//例7-19:重载“=”为成员函数#include<iostream>#include<string>using
namespacestd;className{public:Name(char*str=NULL);Name(Name&s);Name&operator=(Name&);//重载赋值运算符~Name(){deletepName;}voidp
rint(){cout<<pName<<endl;}private:char*pName;};7.7运算符重载2022/11/24北京邮电大学信息与通信工程学院-86-//例7-19:重载“=”为成员函数Name::N
ame(char*str)//构造函数{if(str==NULL)pName=NULL;else{pName=newchar[strlen(str)+1];strcpy(pName,str);}}Name&Name::operator=(Name&s)//重载赋值运算符函数{deletepN
ame;pName=newchar[strlen(s.pName)+1];strcpy(pName,s.pName);return*this;}Name::Name(Name&s)//复制构造函数{pName=newch
ar[strlen(s.pName)+1];strcpy(pName,s.pName);}7.7运算符重载2022/11/24北京邮电大学信息与通信工程学院-87-//例7-19:重载“=”为成员函数voidm
ain(){Names1("DennisWhite"),s2;s2=s1;s2.print();}7.7运算符重载7.8类的组合2022/11/24北京邮电大学信息与通信工程学院-89-7.8类的组合类的组合(也称类的聚集),描述的就是一个类内嵌其它类的对
象作为数据成员的情况,它们之间的关系是一种包含与被包含的关系。在面向对象程序设计中,可以对复杂对象进行分解、抽象,把一个复杂对象分解为简单对象的组合。2022/11/24北京邮电大学信息与通信工程学院-90-当创建组合类的对象时,各个内嵌对象也将被自
动创建。因此,在创建组合类对象时既要对本类的基本数据成员进行初始化,又要对内嵌对象成员进行初始化。在声明一个组合类的对象时,不仅它自身的构造函数将被调用,而且还将调用其内嵌对象的构造函数。7.8类的组合2022/11/24北京邮电大学信息与通信工程学院-
91-组合类构造函数定义的一般形式为:类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表),…{//类的初始化}其中,“内嵌对象1(形参表),内嵌对象2(形参表),…”为初始化列表,用来完成对内嵌对象的初始化。7.8类的组合2022/11/24北
京邮电大学信息与通信工程学院-92-组合类的构造函数的执行顺序是:(1)(如果有多个内嵌对象)按照内嵌对象在组合类的声明中出现的次序,依次调用其内嵌对象的构造函数。(注意:并不是按照初始化列表中给出的顺序)。(2)再执行本类的构造函数的函数
体。7.8类的组合2022/11/24北京邮电大学信息与通信工程学院-93-例如,矩形可以由对角的两个顶点确定其位置和大小,先设计出Point类,再设计出Rectangle类。Rectangle类的两个数据
成员是Point类的对象,这两个点的坐标就决定了矩形的位置和大小。类关系图:7.8类的组合2022/11/24北京邮电大学信息与通信工程学院-94-//例7-20:类的组合应用#include<iostream>#include<cmath>usingna
mespacestd;classPoint//Point类定义{public:Point(intxx=0,intyy=0){X=xx;Y=yy;cout<<"Pointconstructor"<<endl;}~Point(){cout<<"
Pointdestructor"<<endl;}intGetX(){returnX;}intGetY(){returnY;}private:intX,Y;};7.8类的组合2022/11/24北京邮电大学信息与通信工程学院-95-//类的组合classRectangle
//Rectangle类的定义{public://外部接口Rectangle(intx1,inty1,intx2,inty2,intc);~Rectangle();intGetColor(){returncol
or;}intGetWidth(){returnabs(p1.GetX()-p2.GetX());}//求绝对值函数abs()intGetHeight(){returnabs(p1.GetY()-p2.GetY());}
private://私有数据成员Pointp1,p2;//Point类的对象p1,p2intcolor;};7.8类的组合2022/11/24北京邮电大学信息与通信工程学院-96-//组合类的构造函数Rectangle::Rectangle(intx1,inty1,intx2,inty2,in
tc):p1(x1,y1),p2(x2,y2){cout<<"Rectangle构造函数被调用"<<endl;color=c;}Rectangle::~Rectangle(){cout<<"析构Rec
tangle对象"<<endl;}//主函数voidmain(){Rectanglemyr(1,1,4,5,255);//定义Rectangle类的对象cout<<"TheRectangle'scoloris:";cout<<myr.GetC
olor()<<endl;cout<<"TheRectangle'swidthis:";cout<<myr.GetWidth()<<endl;cout<<"TheRectangle'sheightis:";cout<<myr.GetHeight()<<endl;}7.8类的组合7.10
面向对象分析和设计2022/11/24北京邮电大学信息与通信工程学院-98-建立一个大型的软件系统可不是一件简单的事情,它是一项大工程,人们称它为软件工程,它研究如何建立大型软件系统:可靠性;成本效益好;可理解性;可维护性。7
.10面向对象分析与设计2022/11/24北京邮电大学信息与通信工程学院-99-面向对象程序设计是面向对象思想在软件工程领域的全面应用,包括:面向对象分析(OOA),面向对象设计(OOD),面向对象编程(OOP),等。面向对象
分析阶段要把问题的范围定义清楚,分析系统需求,把实际中不重要的东西忽略,对所关心的问题建立一个模型。设计是在分析的基础上进一步加工,OOD阶段是对OOA模型的修改和补充,采用一致的概念、原则和表示法,二者没有严格的阶段
划分,但设计阶段侧重于考虑与实现有关的细节。到了OOP阶段,OOD阶段设计的类被具体的程序设计语言的类所实现。7.10面向对象分析与设计2022/11/24北京邮电大学信息与通信工程学院-100-总结类和对象的基本知识,类的封装性
。对象的构造和析构。构造函数的重载。类的特殊成员:静态成员、常成员。类之间的关系:友元关系、类的组合。