第5章 类和对象1.docx
《第5章 类和对象1.docx》由会员分享,可在线阅读,更多相关《第5章 类和对象1.docx(29页珍藏版)》请在冰豆网上搜索。
第5章类和对象1
第5章类和对象
类是面向对象程序设计的核心,是实现信息封装的基础。
它实际上是一种新的数据类型,是对某一类对象的抽象,而对象是某一种类的实例。
对象和类是密切相关的,没有脱离对象的类,也没有不依赖于类的对象。
5.1类的定义
5.1.1什么是类
类是一种复杂数据类型,它是将不同类型的数据和与这些数据相关的操作封装在一起的集合体。
类是一种用户定义的类型。
有了这种类型使得应用中的实体在程序中可以直接作为一个标识符,对它进行引用和操作。
类是一种用户定义的类型。
有了这种类型使得应用中的实体在程序中可以直接作为一个标识符,对它进行引用和操作。
5.1.2类的定义格式
类的定义包括说明部分
实现部分
说明部分:
说明类中定义的成员。
(数据成员,成员函数)
实现部分:
定义成员函数。
类的定义格式:
class类名
{
public:
成员函数或数据成员的说明
protected:
数据成员或成员函数的说明
private:
数据成员或成员函数的说明
};
各个成员函数的实现
或者:
class类名
{
数据成员或成员函数的说明
public:
成员函数或数据成员的说明
protected:
数据成员或成员函数的说明
};
各个成员函数的实现
public
访问权限protected
Private
公有部分往往是一些操作(成员函数),它是用户的接口。
这部分成员用户在程序中可以使用。
私有部分通常是一些数据成员,是用来描述该类中的对象的属性的,用户无法访问它们,只有成员函数或友元函数才能访问它们。
它们是被用来隐藏的部分。
例如,定义一个日期类。
说明部分:
classTDate
{public:
voidSetDate(inty,intm,intd);
intIsLeapYear();
voidPrint();
private:
intyear,month,day;
};
实现部分:
voidTDate:
:
SetDate(inty,intm,intd)
{year=y;
month=m;
day=d;
}
intTDate:
:
IsLeapYear()
{return(year%4==0&&year%100!
=0)||
(year%400==0);
}
voidTDate:
:
Print()
{cout<<}
:
:
作用域运算符
类名:
:
函数名(参数表)
定义一个日期类还可以:
classTDate
{public:
voidSetDate(inty,intmintd)
{year=y;
month=m;
day=d;}
intIsLeapYear()
{return(year%4==0&&year%100!
=0)||
(year%400==0);}
voidPrint()
{cout<<private:
intyear,month,day;
};
这里实现部分被省略了。
成员函数的作用:
1.操作数据成员,包括访问和修改数据成员;
2.协同不同的对象操作,称为传递消息。
5.1.3定义类时注意事项
1.在类体内不允许对数据成员初始化。
classTDate
{public:
voidSetDate(inty,intmintd);
intIsLeapYear();
voidPrint();
private:
intyear(2004),month(9),day(29);
};
2.类中数据成员的类型是任意的。
整形、实型、字符型、数组、指针、引用和类类型等。
另一个类的对象,可以作该类的成员,但自身类的对象不行。
例1:
classstudent
{public:
……
private:
longcode;
charname[10];
TDatebirthday;//类类型成员
char*address;
charphone[20];
};
例2:
classN;//类说明
classM
{public:
……
private:
classNn;//n是N的对象
};
classN
{public:
voidf(Mn);//m是M类的对象
……
};
3.经常习惯地将类定义的说明部分或整个类的定义放到一个头文件中。
例如,定义一个点类,放在tpoint.h文件中。
classTpoint
{public:
voidSetPoint(intx,inty);
intXcoord(){returnX;}
intYcoord(){returnY;}
voidMove(intxoffset,intyoffset);
private:
intX,Y;
};
voidTpoint:
:
SetPoint(intx,inty)
{X=x;
Y=y;
}
voidTpoint:
:
Move(intxoffset,intyoffset)
{X+=xoffset;
Y+=yoffset;
}
5.2对象的定义
对象是类的实例。
对象是属于某个已知的类。
5.2.1对象的定义格式
定义格式:
类名对象名
例如:
TDatedate1,date2,*p,date[10];
Tpointp1,p2,*p,&d=p1;
5.2.2对象成员的表示方法
对象成员数据成员
成员函数
对象数据成员的表示:
对象名.成员名
例如:
date1.year,date1.month,date1.day
对象函数成员的表示:
对象名.成员名(参数表)
例如:
date1.SetDate(2004,9,28)
其中“.”是一个运算符。
指向对象的指针的成员:
对象指针名->成员名
例如:
Pdate->year
或者:
对象指针名->成员名(参数表)
例如:
Pdate->SetDate(2004,9,28)
下面两种表示相同:
对象指针名->成员名
*对象指针名.成员名
例如:
Pdate->year
*Pdate.year
例5.1分析输出结果。
tdate.h
classTDate
{public:
voidSetDate(inty,intm,intd)
{year=y;
month=m;
day=d;}
intIsLeapYear()
{return(year%4==0&&year%100!
=0)||
(year%400==0);}
voidPrint()
{cout<<private:
intyear,month,day;
};
#include
#include”tdate.h”
voidmain()
{TDatedate1,date2;
date1.SetDate(2004,10,8);
date2.SetDate(2005,10,8);
intleap1=date1.IsLeapYear();
cout<intleap2=date2.IsLeapYear();
cout<date1.Print();
date2.Print();
}
输出:
1
0
2004.10.8
2005.10.8
例5.2
#include
#include”tpoint.h”
voidmain()
{
Tpointp1,p2;
p1.SetPoint(3,5);
p2.SetPoint(8,10);
p1.Move(2,1);
p2.Move(1,-2);
cout<<”x1=”<<cout<<”x2=”<<}
结果:
x1=5,y1=6
x2=9,y2=8
例5.3访问对象的公有成员。
#include
classTclass
{public:
intx,y;
voidprint()
{cout<};
voidmain()
{Tclasstest;
test.x=100;
test.y=200;
test.print();
}
输出:
100,200
例5.4用指针访问对象的公有成员。
#include
classTclass
{public:
intx,y;
voidprint()
{cout<};
intadd(Tclass*ptf)
{return(ptf->x+ptf->y);}
voidmain()
{Tclasstest,*pt=new(Tclass);
pt->x=100;
pt->y=200;
pt->print();
test.x=150;
test.y=450;
test.print();
cout<<”x+y=”<}
输出:
100,200
150,450
x+y=600
5.3对象的初始化
5.3.1构造函数和析构函数
构造函数的格式:
类名:
:
构造函数名(参数表)
{}
构造函数的功能:
是在创建对象时,使用给定的值为对象初始化。
析构造函数的格式:
类名:
:
~析构函数名()
{}
析构函数的功能:
是用来释放一个对象。
例5.5重新定义日期类
//tdate1.h
classTDate1
{public:
TDate1(inty,intm,intd);
~TDate1();
voidIsLeapYear();
voidPrint();
private:
intyear,month,day;
};
TDate1:
:
TDate1(inty,intm,intd)
{year=y;
month=m;
day=d;
cout<<”Constructorcalled.\n”;
}
TDate1:
:
~TDate1()
{cout<<”Destructorcalled.\n”;}
voidTDate1:
:
IsLeapYear()
{if(year%4==0&&year%100!
=0||
year%400==0)
cout<<”Isleapyear.\n”;
else
cout<<”Isnotleapyear.\n”;
}
voidTDate1:
:
Print()
{cout<<}
#include
#include”tdate1.h”
voidmain()
{TDate1today(2004,10,8),
tomorrow(2004.10,9);
cout<<”todayis“;
today.Print();
today.IsLeapYear();
cout<<”tomorrowis“;
tomorrow.Print();
}
输出:
ConstructorCalled.
ConstructorCalled.
todayis2004.10.8
Isleapyear.
tomorrowis2004.10.9
DestructorCalled.
DestructorCalled.
构造函数的特点:
1.构造函数是成员函数。
2.构造函数与类同名,不指定函数类型。
3.构造函数可以重载。
4.在创建对象时系统自动调用构造函数,在程序中不能直接调用构造函数。
析构函数的特点:
1.析构函数是成员函数。
2.析构造函数与类同名,并在前面加“~”字符,不指定函数类型,也没有参数。
3.一个类中只可以定义一个析构函数。
4.系统可以自动调用析构函数,在程序中也可以直接调用析构函数。
5.3.2缺省构造函数和缺省析构函数
缺省构造函数的格式:
类名:
:
缺省构造函数名()
{}
缺省构造函数在类中没有定义任何构造函数时系统自动生成;也可以用户自己定义。
例如:
Tpointp1,p2;
缺省构造函数对p1和p2进行初始化。
对象的所有数据成员都是不确定的。
缺省析构函数的格式:
类名:
:
~缺省析构函数名()
{}
缺省析构函数在类中没有定义析构函数时系统自动生成,是一个空函数。
例5.6重新定义日期类
//tdate2.h
classTDate2
{public:
TDate2();
~TDate2();
voidSetDate(inty,intm,intd);
voidIsLeapYear();
voidPrint();
private:
intyear,month,day;
};
TDate2:
:
TDate2()
{cout<<”Constructorcalled.\n”;}
TDate2:
:
~TDate2()
{cout<<”Destructorcalled.\n”;}
voidTDate2:
:
SetDate(inty,intm,intd)
{year=y;
month=m;
day=d;
}
voidTDate2:
:
IsLeapYear()
{if(year%4==0&&year%100!
=0||
year%400==0)
cout<<”Isleapyear.\n”;
else
cout<<”Isnotleapyear.\n”;
}
voidTDate2:
:
Print()
{cout<<}
#include
#include”tdate2.h”
voidmain()
{TDate2d;
cout<<”dis“;
d.Print();
d.SetDate(2004,10,8);
cout<<”dis“;
d.Print();
}
输出:
Constructorcalled.
dis-858993460,-858993460,-858993460
dis2004.10.8
Destructorcalled.
例5.7重新定义日期类
//tdate3.h
classTDate3
{public:
TDate3(int,int,int);
~TDate3();
voidSetDate(inty,intm,intd);
voidIsLeapYear();
voidPrint();
private:
intyear,month,day;
};
TDate3:
:
TDate3(inty,intm,intd)
{year=y;month=m;day=d;
cout<Constructorcalled.\n”;}
TDate3:
:
~TDate3()
{cout<<<”:
Destructorcalled.\n”;}
voidTDate3:
:
SetDate(inty,intm,intd)
{year=y;month=m;day=d;}
voidTDate3:
:
IsLeapYear()
{if(year%4==0&&year%100!
=0||
year%400==0)
cout<<”Isleapyear.\n”;
else
cout<<”Isnotleapyear.\n”;
}
voidTDate3:
:
Print()
{cout<<}
#include
#include”tdate3.h”
voidmain()
{TDate3d1(2000,5,1);
TDate3d2(2001,10,1);
d1.SetDate(1998,6,15);
d1.Print();
d1.IsLeapYear();
d1.SetDate(2000,9,23);
d1.Print();
d1.IsLeapYear();}
输出:
2000.5.1:
Constructorcalled.
2001.10.1:
Constructorcalled.
1998.6.15
Isnotleapyear.
2000.9.23
Isleapyear.
2001.10.1:
Destructorcalled.
2000.9.23:
Destructorcalled.
对象的构造和析构次序是相反的,先建立的对象后析构。
例5.8定义图书卡片类。
#include
#include
classCard
{public:
Card(char*t,char*name,intnum);
voidshow();
private:
chartitle[80];
charauthor[40];
intnumber;
};
Card:
:
Card(char*t,char*name,intnum)
{strcpy(title,t);
strcpy(author,name);
number=num;
}
voidCard:
:
show()
{cout<<”Title:
”<
cout<<”Author:
”<cout<<”Number:
”<}
voidmain()
{Cardbook1(“Basic”,”Tang”,10);
Cardbook2(“FORTRAN”,”Wang”,20);
book1.show();
book2.show();
}
输出:
Title:
Basic
Author:
Tang
Number:
10
Title:
FORTRAN
Author:
Wang
Number:
20
构造函数还有一种称为“初始式”的形式对数据成员置初值。
形式为:
构造函数名(参数表):
数据成员1(参数),
数据成员2(参数),…
{……}
例如:
TDate3:
:
TDate3(inty,intm,intd)
{year=y;month=m;day=d;
cout<<”:
Constructorcalled.\n”;}
可以:
TDate3:
:
TDate3(inty,intm,intd):
year(y),month(m),day(d)
{cout<<”:
Constructorcalled.\n”;}
例5.8对象成员初始化
#include
classA
{public:
A(intx):
a(x){}
inta;
};
classB
{public:
B(intx,inty):
aa(x),b(y){}
voidout()
{cout<<”aa=”<<
private:
intb;
Aaa;
};
voidmain()
{BobjB(3,5);
objB.out();
}
输出:
aa=3
b=5
以上不能:
B(intx,inty)
{aa.a=x;b=y;}不能在构造函数中对类成员赋值
但可以:
B(intx,inty):
aa(x)
{b=y;}
5.3.3拷贝初始化构造函数
功能:
是用一个已知的对象来初始化一个被创建的同类的对象。
格式:
类名:
:
拷贝初始化构造函数名(const类名&引用名)
特点:
1.也是一种构造函数,函数名同类名。
2.只有一个参数,并且是对某个对象的引用。
3.如果类中没有说明拷贝初始化构造函数,则系统自动生成一个缺省拷贝初始化构造函数。
例5.9修改点类的定义。
//tpoint1.h
classTPoint
{public:
TPoint(intx,inty){X=x;Y=y;}
TPoint(TPoint&p);
~TPoint()
{cout<<”DestructorCalled.\n”;}
intXcoord(){returnX;}
intYcoord(){returnY;}
private:
intX,Y;
};
TPoint:
:
TPoint(TPoint&p)
{X=p.X;
Y=p.Y;
cout<<”Copy_initializationConstructorCalled.\n”;}
#include
#include”tpoint1.h”
voidmain()
{TPointP1(5,7);
TPointP2(P1);
cout<<”P2=”<<输出:
Copy_initializationConstructorCalled.
P2=5,7
DestructorCalled.
DestructorCalled.
例5.10拷贝初始化构造函数的其他用法。
#include
#include”tpoint1.h”
TPointf(TPointQ);
voidmain()
{TPoin