第5章 类和对象(一)9/12/20241陕西科技大学计算机系陕西科技大学计算机系5.1 类的定义§类是通过抽象数据类型的方法来实现的一种数据类型;§类是面向对象程序设计的核心;§类是对某一类对象的抽象,对象是某一种类的实例;§类是C++实现抽象数据类型的工具;9/12/20242陕西科技大学计算机系陕西科技大学计算机系5.1.1 什么是类§类是一种复杂数据类型,它是将不同类型的数据和与这些数据相关的操作封装在一起的集合体;§类具有更高的抽象性,类中的数据具有隐藏性;9/12/20243陕西科技大学计算机系陕西科技大学计算机系5.1.2 类的定义格式§说明部分:说明该类中的成员,包含数据成员的说明和成员函数的说明;§实现部分:对成员函数的定义;1、类定义格式的构成2、类的一般定义格式 class <类名> { public: <成员函数或数据成员的说明> private: <数据成员或成员函数的说明> }; <各个成员函数的实现>访问权限类定义关键字说明部分实现部分语句结束符9/12/20244陕西科技大学计算机系陕西科技大学计算机系5.1.2 类的定义格式(续)§访问权限修饰符:公有的(public)、私有的(private)和保护的(protected);§访问权限修饰符出现的先后次序无关,并且允许多次出现;3、类定义的说明§缺省访问权限为私有的;§公有部分:一些操作(即成员函数),是提供给用户的接口功能;§私有部分:一些数据成员,通常用来描述该类中的对象的属性;9/12/20245陕西科技大学计算机系陕西科技大学计算机系5.1.2 类的定义格式(续)4、示例(tdate.h)class TDate{public: void SetDate(int y,int m,int d); int IsLeapYear(); void Print();private: int year,month,day;};void TDate::SetDate(int y,int m,int d){ year=y; month=m;成员函数定义作用域运算符9/12/20246陕西科技大学计算机系陕西科技大学计算机系5.1.2 类的定义格式(续) day=d;}int TDate::IsLeapYear(){ return (year%4==0 && year%100!=0)|| (year%400==0)}void TDate::Print(){ cout<::<函数名>(<参数表>)9/12/20247陕西科技大学计算机系陕西科技大学计算机系5.1.3 定义类时的注意事项§在类体中不允许对所定义的数据成员进行初始化; class TDate { public: …... private: int year(1998),month(4),day(9); };错误§类中的数据成员的类型可以是任意的;k包含整型、浮点型、字符型、数组、指针和引用等;k另一个类的对象,可以作该类的成员;k自身类的对象不不可以作该类的成员;9/12/20248陕西科技大学计算机系陕西科技大学计算机系5.1.3 定义类时的注意事项(续)class N;class M{ public: …... private: N *n;};class N{ public: void f(M m); ……};提前说明类Nk自身类的指针或引用,可以作该类的成员;k当另一个类的对象作为该类的成员时,如果另一个类的定义在后,需要提前说明;k一般在类体内先说明用户感兴趣的公有成员,再说明私有成员;k习惯将类定义的说明部分或者整个定义部分(包含实现部分)放到一个头文件中;n是N类的对象m是M类的对象9/12/20249陕西科技大学计算机系陕西科技大学计算机系5.2.1 对象的定义格式例如: TDate date1,date2,*Pdate,date[31];<类名> <对象名表>;对象的定义格式。
9/12/202410陕西科技大学计算机系陕西科技大学计算机系5.2.2 对象成员的表示方法1、一般对象数据成员: <对象名>.<成员名>成员函数: <对象名>.<成员名>(<参数表>).运算符:表示对象的成员例如: date1.year, date1.month, date1.day; date1.SetDate(1998,4,9);2、指针对象数据成员: <对象名>-><成员名>成员函数: <对象名>-><成员名>(<参数表>)->运算符:表示对象的成员例如:Pdate->year, Pdate->SetDate(1998,4,9);9/12/202411陕西科技大学计算机系陕西科技大学计算机系5.2.2 对象成员的表示方法(续)§->运算符与.运算符的区别->表示指向对象的指针的成员;.表示一般对象的成员;§两种等价表示<对象指针名>-><成员名>(*<对象指针名>).<成员名>3、引用对象与一般对象相同;9/12/202412陕西科技大学计算机系陕西科技大学计算机系5.2.2 对象成员的表示方法(续)#include #include "tdate.h"void main(){ TDate date1,date2; date1.SetDate(1996,5,4); date2.SetDate(1998,4,9); int leap=date1.IsLeapYear(); cout<
9/12/202413陕西科技大学计算机系陕西科技大学计算机系5.3.1 构造函数和析构函数1、构造函数与析构函数的功能§特殊的成员函数;§构造函数:在创建对象时,使用特定的值来将对象初始化;§析构函数:用来释放对象,在对象删除前做一些清理工作;9/12/202414陕西科技大学计算机系陕西科技大学计算机系5.3.1 构造函数和析构函数(续)§示例(tdate1.h)class TDate1{public: TDate1(int y,int m,int d); ~TDate1(); void Print();private: int year,month,day;};TDate1::TDate1(int y,int m,int d){ year=y; month=m;构造函数析构函数9/12/202415陕西科技大学计算机系陕西科技大学计算机系5.3.1 构造函数和析构函数(续) day=d; cout<<"Constructor called. "<#include "tdate1.h"void main(){ TDate1 today(1998,4,9), tomorrow(1998,4,10); cout<<"Today is "; today.Print(); cout<<"Tomorrow is "; tomorrow.Print();}输出:Constructor called.Constructor called.Today is 1998.4.9Tomorrow is 1998.4.10Destructor called.Destructor called.例5.3:分析下列程序的输出结果。
9/12/202419陕西科技大学计算机系陕西科技大学计算机系5.3.2 缺省构造函数和缺省析构函数 <类名>::<缺省构造函数名>() { }1、缺省构造函数§类定义中没有任何构造函数时,由编译器自动生成一个不带参数的缺省构造函数;§缺省构造函数即参数表为空的构造函数; <类名>::~<缺省析构函数名>() { }2、缺省析构函数(定义时机同缺省构造函数)类名9/12/202420陕西科技大学计算机系陕西科技大学计算机系5.3.3 拷贝初始化构造函数1、功能 用一个已知的对象来初始化一个被创建的同类对象;2、特点§函数名同类名,无返回类型;§只有一个参数,是对某个对象的引用;§每个类都必须有一个拷贝初始化构造函数;<类名>::<类名>(const <类名>& <引用名>)3、缺省拷贝初始化构造函数 如果类中没有说明拷贝初始化构造函数,则编译系统自动生成一个具有上述形式的缺省拷贝初始化构造函数,作为该类的公有成员;9/12/202421陕西科技大学计算机系陕西科技大学计算机系5.3.3 拷贝初始化构造函数(续)//tpoint.hclass TPoint{public:{ TPoint(int x,int y) {X=x;Y=y;} TPoint(TPoint &p); ~TPoint() {cout<<"Destructor called."<
构造函数拷贝初始化构造函数9/12/202422陕西科技大学计算机系陕西科技大学计算机系5.3.3 拷贝初始化构造函数(续)TPoint::TPoint(TPoint &p){ X=p.X; Y=p.Y; cout<<"Copy_initialization Constructor called.\n";}#include #include "tpoint1.h"TPoint f(TPoint Q);void main(){ TPoint M(20,35),P(0,0); TPoint N(M);M为已知对象,N是正在创建的对象9/12/202423陕西科技大学计算机系陕西科技大学计算机系5.3.3 拷贝初始化构造函数(续) P=f(N); cout<<"P="<& <类名>::operator =(const <类名>& <引用名>)B=A;等价于 B.operator =(A);§每个类都有一个赋值操作;9/12/202428陕西科技大学计算机系陕西科技大学计算机系5.3.4 赋值(续)#include class Location{public:{ Location(int xx=0,int yy=0) {X=xx;Y=yy;} Location(Location &p) {X=p.X;Y=p.y;} Location& operator =(Location& p); int GetX() {return X;} int GetY() {return Y;}private: int X,Y;};例5.4:分析下列程序的输出结果。
赋值函数9/12/202429陕西科技大学计算机系陕西科技大学计算机系5.3.4 赋值(续)Location& Location::operator =(Location& p){ X=p.X; Y=p.Y; cout<<"Assignment operator called."<
也可以直接在类中给出函数体,形成内联成员函数§允许声明重载函数和带默认形参值的函数9/12/202434陕西科技大学计算机系陕西科技大学计算机系5.4.1 内联函数和外联函数§内联函数:定义在类体内的成员函数,或定义在类体外,但使用inline关键字进行说明的成员函数;§外联函数:说明在类体内,定义在类体外的成员函数;9/12/202435陕西科技大学计算机系陕西科技大学计算机系5.4.1 内联函数和外联函数(续)例5.6:分析下列程序的输出结果include class A{public: A(int x,int y) {X=x;Y=y;} int a() {return X;} int b() {return Y;} int c(); int d();private: int X,Y;};内联函数9/12/202436陕西科技大学计算机系陕西科技大学计算机系5.4.1 内联函数和外联函数(续)inline A::c(){ return a()+b();}inline int A::d(){ return c();}void main(){ A m(3,5); int i=m.d(): cout<<"d() return:"<
include class M{public: M(int x,int y) {X=x;Y=y;} M(int x) {X=x;Y=x*x;} int Add(int x,int y); int Add(int x); int Add(); int Xout() {return X;} int Yout() {return Y;}private: int X,Y;};构造函数重载一般成员函数重载9/12/202439陕西科技大学计算机系陕西科技大学计算机系5.4.2 重载性(续)int M::Add(int x,int y){ X=x; Y=y; return X+Y;} int M::Add(int x){ X=Y=x; return X+Y;}int M::Add(){ return X+Y;}9/12/202440陕西科技大学计算机系陕西科技大学计算机系5.4.2 重载性(续)void main(){ M a(10,20),b(4); cout<<"a="<
9/12/202442陕西科技大学计算机系陕西科技大学计算机系5.4.3 设置参数的缺省值(续)例5.8:分析下列程序的输出结果include class N{public: N(int a=3,int b=5,int c=7); int Aout() {return A;} int Bout() {return B;} int Cout() {return C;}private: int A,B,C;};int N::N(int a,int b,int c)构造函数设置缺省参数值9/12/202443陕西科技大学计算机系陕西科技大学计算机系5.4.3 设置参数的缺省值(续){ A=a; B=b; C=c;}void main(){ N X,Y(9,11),Z(13,15,17); cout<<"X="<
9/12/202445陕西科技大学计算机系陕西科技大学计算机系5.5.1 静态数据成员1、静态数据成员§是类的所有对象共享的成员,而不是某个对象的成员;§对多个对象来说,静态数据成员只存储在一个地方,供所有对象使用;§静态数据成员的值对每个对象都是一样的,但其值可以被任何一个对象更新;2、使用方法与注意事项§静态数据成员在定义或说明时前面加上关键字static; private: static int s;s是私有的静态数据成员;9/12/202446陕西科技大学计算机系陕西科技大学计算机系5.5.1 静态数据成员(续)§静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化;§静态数据成员的初始化与一般数据成员初始化不同,格式如下:§说明:k初始化在类体外进行,前面不加static,以免与一般静态变量或对象混淆;<数据类型> <类名>::<静态数据成员名>=<值>;k初始化时不加该成员的访问权限控制符(静态数据成员初始化位置与访问权限无关);k初始化时使用作用域运算符表明它所属的类;k引用格式: <类名>::<静态成员名>9/12/202447陕西科技大学计算机系陕西科技大学计算机系5.5.1 静态数据成员(续)例5.10:分析下列程序的输出结果。
include class Myclass{public: Myclass(int a,int b,int c); void GetNumber(); void GetSum();private: int A,B,C; static int Sum;};int Myclass::Sum=0;私有静态数据成员Sum静态数据成员Sum初始化9/12/202448陕西科技大学计算机系陕西科技大学计算机系5.5.1 静态数据成员(续)Myclass::Myclass(int a,int b,int c){ A=a; B=b; C=c; Sum+=A+B+C;}void Myclass::GetNumber(){ cout<<"Number="<::<静态成员函数名>(<参数表>)9/12/202451陕西科技大学计算机系陕西科技大学计算机系5.5.2 静态成员函数(续)例5.11:分析下列程序的输出结果。
include class M{public: M(int a) {A=a;B+=a;} static void f1(M m);private: int A; static int B;};void M::f1(M m){私有静态数据成员B公有静态成员函数静态成员函数体9/12/202452陕西科技大学计算机系陕西科技大学计算机系5.5.2 静态成员函数(续) cout<<"A="<::<静态成员函数名>(<参数表>)通过对象引用非静态成员直接引用静态成员私有静态数据成员初始化输出 A=5 B=15 A=10 B=159/12/202453陕西科技大学计算机系陕西科技大学计算机系5.5.2 静态成员函数(续)例5.10: 某商店经销一种货物,货物成箱购进,成箱卖出,购进和卖出时以重量为单位,各箱的重量不一样,因此,商店需要记录下目前库存的货物的总重量,现在要求用C++语言来模拟商店货物购进和卖出的情况。
9/12/202454陕西科技大学计算机系陕西科技大学计算机系5.5.2 静态成员函数(续)#include class Goods{public: Goods(int w); ~Goods(); int Weight(); static int TotalWeight();private: int weight; static int totalWeight;};Goods::Goods(int w){现有库存货物购进货物卖出9/12/202455陕西科技大学计算机系陕西科技大学计算机系5.5.2 静态成员函数(续) weight=w; totalWeight+=w;}Goods::~Goods(){ totalWeight-=weight;}int Goods::Weight(){ return weight;}int Goods::TotalWeight(){ return totalWeight;}9/12/202456陕西科技大学计算机系陕西科技大学计算机系5.5.2 静态成员函数(续)int Goods::totalWeight=0;void main(){ int w; cin>>w; Goods g1(w); cin>>w; Goods g2(w); cout<
§通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息§可以使用友元函数和友元类§为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元9/12/202458陕西科技大学计算机系陕西科技大学计算机系5.6 友元1、为什么引入友元 在对某些成员函数多次调用时,由于参数传递、类型检查和安全性检查等都需要时间开销,从而影响了程序的运行效率,引入友元后可以提高程序的运行效率;增加灵活性,使程序员可以在封装和快速性方面做合理选择9/12/202459陕西科技大学计算机系陕西科技大学计算机系§友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和 protected成员§作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择§访问对象中的成员必须通过对象名5.6.1 友元函数9/12/202460陕西科技大学计算机系陕西科技大学计算机系例5.12:使用友元函数计算两点距离#include #include using namespace std;class Point//Point类声明{ public://外部接口Point(int xx=0, int yy=0) {X=xx;Y=yy;}int GetX() {return X;}int GetY() {return Y;}friend float Distance(Point &a, Point &b); private://私有数据成员int X,Y;};5.6.1 友元函数9/12/202461陕西科技大学计算机系陕西科技大学计算机系double Distance( Point& a, Point& b){ double dx=a.X-b.X; double dy=a.Y-b.Y; return sqrt(dx*dx+dy*dy);}int main(){ Point p1(3.0, 5.0), p2(4.0, 6.0); double d=Distance(p1, p2); cout<<"The distance is "<
include class Time{public: Time(int new_hours,int new_minutes) {hours=new_hours;minutes=new_minutes;} friend void Time12(Time time); friend void Time24(Time time);private: int hours,minutes;};void Time12(Time time){友元函数的定义友元函数的说明9/12/202463陕西科技大学计算机系陕西科技大学计算机系5.6.1 友元函数例5.13:分析下列程序的输出结果include class Time{public: Time(int new_hours,int new_minutes) {hours=new_hours;minutes=new_minutes;} friend void Time12(Time time); friend void Time24(Time time);private: int hours,minutes;};void Time12(Time time){友元函数的定义友元函数的说明9/12/202464陕西科技大学计算机系陕西科技大学计算机系5.6.1 友元函数(续) if(time.hours>12) { time.hours-=12; cout<
§声明语法:将友元类名在另一个类中使用friend修饰说明5.6.2 友元类9/12/202467陕西科技大学计算机系陕西科技大学计算机系5.6.2 友元类例5.14:分析下列程序的输出结果include class X{ friend class Y;public: void Set(int i) {x=i;} void Display() {cout<<"x="<
类域介于文件域和函数域之间5.7 类的作用域(了解) 9/12/202471陕西科技大学计算机系陕西科技大学计算机系n局部类:l在一个函数体内定义的类成为局部类l局部类中不能说明静态成员函数l所有成员函数必须定义在类体内l很少用,了解即可5.8 局部类和嵌套类(了解) n嵌套类l在一个类中定义的类称为嵌套类l定义嵌套类的类称为外围类l目的在于隐藏类名,减少全局的标识符,从而限制用户能否使用该类建立对象9/12/202472陕西科技大学计算机系陕西科技大学计算机系5.9 对象的生存期1、对象的生存期 指对象从被创建开始到被释放为止的时间;§局部对象:被定义在一个函数体或程序块内,作用域小,生存期短;2、按生存期对对象的分类§静态对象:被定义在一个文件中,它的作用域从定义时起到文件结束时止;它的作用域较大,生存期也较长;§全局对象:被定义在某个文件中,它的作用域在包含该文件的整个程序中;它的作用域最大,生存期最长;9/12/202473陕西科技大学计算机系陕西科技大学计算机系例5-3具有静态、动态生存期对象的时钟程序#includeusing namespace std;class Clock //时钟类声明{public://外部接口Clock();void SetTime(int NewH, int NewM, int NewS); //三个形参均具有函数原型作用域void ShowTime();~Clock(){}private://私有数据成员int Hour,Minute,Second;};9/12/202474陕西科技大学计算机系陕西科技大学计算机系//时钟类成员函数实现Clock::Clock()//构造函数{ Hour=0;Minute=0;Second=0;}void Clock::SetTime(int NewH, int NewM, int NewS){ Hour=NewH;Minute=NewM;Second=NewS;}void Clock::ShowTime(){ cout<
include #include class A{public: A(char *st); ~A(); private: char string[50];};A::A(char *st){ strcpy(string,st); cout<<"Constructor called for "<