C++教程第07章类与对象1定义及使用初步Word格式.docx
《C++教程第07章类与对象1定义及使用初步Word格式.docx》由会员分享,可在线阅读,更多相关《C++教程第07章类与对象1定义及使用初步Word格式.docx(15页珍藏版)》请在冰豆网上搜索。
通过友员,一个普通函数或另一个类的成员函数可以访问其他类中的私有和保护成员。
7-5.第7章类与对象-练习
7-5-1.思考题:
1).什么是类?
类的一般形式是什么?
2).比较C++中的结构和类的异同。
3).什么是对象,类和对象之间有什么样的关系?
4).对象能够访问什么类型的成员?
如何访问?
5).*this指针具有什么样的特殊性?
在编程过程中如何使用*this指针?
6).在类中是如何实现封装性的?
7).构造函数与析构函数分别有什么用?
为什么允许构造函数重载而不允许析构函数重载。
8).如何实现对象成员的初始化?
试举例说明。
9).const对象具有什么特征?
在使用const对象时的注意点是什么?
10).如何声明一个友元函数?
一个类的友元函数是如何访问该类的成员的?
11).静态成员数据具有什么特征?
在什么情况下使用静态成员数据?
12).静态成员函数具有什么特征?
在定义静态成员函数时要注意什么?
7-5-2.练习题:
课后练习题见练习单元。
第7章类与对象课件
7.1类和对象
7.1.1类
类:
是对一组具有公共属性的事物的抽象,从语言角度讲,它是一种自定义的数据类型,其中既包含有描述其属性的数据,又有处理这些数据的操作(函数),
7.1.1.1类的定义
类的格式与结构(struct)类似。
一般格式如下:
class<
类名>
{
《《private:
:
》
〈私有成员数据和成员函数〉;
《public:
〈公有成员数据和成员函数〉;
《protected:
〈保护成员数据和成员函数〉》
};
其中:
1)class是定义类的关键字;
2)〈类名〉为一个合法的标识符,是类的命名。
3)类体:
一对大括号内的说明部分。
类体后面有个分号,表示类体的结束。
4)类的成员:
类体中定义的数据和函数。
称为:
成员数据和成员函数。
5)private:
限定的成员为私有成员。
私有成员只限定在该类的内部使用。
即只允许该类中的成员函数访问私有的成员数据和私有的成员函数。
punlic:
限定的成员称为公有成员。
可以被类中的成员函数和类外的函数使用(访问—对数据或调用—对函数)。
protected:
限定的成员称为保护成员,对保护成员的访问要求与私有成员类似,只是在有派生类时与私有成员不同。
6)private、public、protected在类中的顺序无关紧要的,同一个关键字在类体中可以被反复使用。
7)private为默认关键字,在类体中没有明确地指定成员的访问权限时,系统约定这些成员为私有成员。
8)限定访问权限的关键字的限定范围为:
从该关键字后的第一个成员开始,到下一个限定访问权限的关键字之间的所有的成员。
9)在定义类时,类的成员顺序也是无关紧要的,可先定义成员数据,也可以先定义成员函数,也可以混在一起定义,此时在前面定义的成员函数可以访问在后面定义的成员,在后面定义的成员函数也可以访问在前面定义的函数。
但为了使定义的类清晰易懂,通常将成员数据集中在一起定义。
10)类可以嵌套定义,见下例。
例如:
7.1.1定义一个表示日期的类
classCDate
private:
//
intyear,month,day;
public:
voidSetDate(inty,intm,intd)
{
year=y;
month=m;
day=d;
}
voidPrint()
cout<
<
year<
”年”<
month<
”月”<
day<
”日”;
}
};
类的嵌套,在一个类体中可以定义另一个类,这一点与函数不同。
classCOuter
classCInner
inti;
CInnerx;
7.1.1.2类的构成
类的成员的定义:
1.类的数据成员定义:
通常都在类体内定义,它的定义方式和变量的定义方式相同。
类的数据成员可以是基本数据类型、导出数据类型或指针类型,也可
以是用户自定义类型。
2.类的成员函数:
1)定义与一般的函数类似,可有参数和返回类型,
2)其函数体可以在类体内定义也可以在类体外定义,这两种定义方式使用效果相同。
在类体内实现的成员函数都是内联函数(见第3章),称为内联成员函数,在类体外实现的成员函数称为外联成员函数,不是内联函数,但可以在函数实现时在其函数名前加上关键字inline来表示该函数是内联成员函数。
3)一般来说,一个类必须至少有一个公有成员函数,否则该类不能与外界交互。
4)类的成员函数也称为消息,根据访问权限的不同,可将其分为公有消息和私有消息。
私有和保护成员函数只能被类的成员函数或友员函数访问,称它们为私有消息;
公有成员函数不仅可以被内部成员访问,而且能够被外部成员访问,则称它们为公有消息。
对于一个具有封装性的类,主要通过公有消息与外界交互。
3.定义类时,只是定义了一种数据类型,此时并没有给所定义的类分配存储空间,因此这时不能对类中的成员数据初始化。
由于类的定义,是将一些数据和函数封装在一个统一的体中,所以所以类的成员数据不能使用关键字extern、auto以及register等(static除外)来限定其存储类型。
classCDate{
intyear=2002,month=1;
//错误,不能对类定义中的数据成员初始化
registerintday;
//错误,不能限定类中数据成员的存储类型
---
4.类中的成员具有类作用域:
类中的成员的有效范围为整个类体,它们能供类中的成员函数访问,类中的成员函数可以访问类中的任何成员,且不受位置的限制,即在类中先定义的成员函数可以访问后定义的其他成员。
5.在类体外定义成员函数,一定要在成员函数前加上“类名:
”,(:
称为作用域运算符或作用域限定符)
例7.1.2在类体外实现成员函数的定义。
public:
voidSetDate(inty,intm,intd)//在类体内实现的函数,为内联函数
{
month=m;
voidPrint();
intIsLeapYear();
private:
intyear,month,day;
voidCDate:
Print()
cout<
day<
inlineintCDate:
IsLeapYear()//在类体外定义内联函数
return(year%4==0&
&
year%100!
=0)||(year%400==0);
7.1.2类的使用
类是一种导出数据类型,或称用户自定义的数据类型,定义类之后,就可以用它来说明变量,具有类类型的变量称为类的对象,或称为类的实例。
在程序中定义对象的语法和定义变量相同。
7.1.2.1对象的创建
定义对象的方法,一般格式为:
〈〈存储类型〉〉〈类名〉〈对象名1〉〈〈,〈对象名2〉,---〉〉;
〈〈存储类型〉〉:
指定了对象的存储类型,是可选的,默认为自动(auto)类型
〈类名〉:
为用户自定义类的名字;
〈对象名〉:
是所要创建的对象的名字,它可为任意的合法的标识符。
可用例9.1中的类CDate创建如下的两个对象:
1.CDatet1,t2;
2.在定义类的同时创建对象:
ClassCCreate
intx,y;
public:
voidPrint(void)
{cout<
x<
’\t’<
y<
’\n’;
}r1,r2;
//定义类的同时定义对象
3.在创建对象的同时允许对它的公有成员数据用一种特殊方式进行初始化,称为初始化列表法。
注意,不允许用这种方式,对对象的私有或保护成员函数进行初始化。
class{
intx,y;
}x1,x2={58,68};
//不定义类名,直接创建对象,对第二个对象初始化
4.在创建对象时,编译系统只为对象中的成员数据分配存储空间。
而同类对象的成员函数的代码却是共享,即将类的成员函数的代码被存放到一个公用区中,为该类所有的对象所共用,而不是为每一个对象复制一份成员函数的代码,这样就节省了大量的内存空间。
7.1.2.2对象的使用
对象只能访问公有成员。
一般格式:
〈对象名〉·
〈公有成员数据名〉
或
〈公有成员函数名〉(〈参数表〉)
“·
”称为成员选择运算符。
访问对象的成员函数也称为向对象发送一个消息。
只能访问公有成员,而不能访问私有成员或保护成员。
对象只能通过公有成员函数间接地访问其私有成员或保护成员。
例7.1.3(P227)定义一个描述线段的类,要求能够设置该线段,并能获取其坐标值以及该线段的长度。
#include<
iostream.h>
#include<
math.h>
classCline{
floatx1,y1;
floatx2,y2;
voidSetCoord(float,float,float,float);
//设置坐标值函数
floatGetCoordX1(){returnx1;
}//获取第一个端点的横坐标
floatGetCoordY1(){returny1;
}//获取第一个端点的纵坐标
voidPrint(void)
floatL;
L=sqrt((y2-y1)*(y2-y1)+(x2-x1)(x2-x1));
“该直线的长度为:
”<
L<
‘\n’;
voidCline:
SetCoord(floata1,floatb1,floata2,floatb2)
{x1=a1;
y1=b1;
x2=a2;
y2=b2;
voidmain(void)
Clineline1,line2;
line1·
SetCoord(50,60,100,200);
”x1=”<
line1·
GetCoordX1()<
’\n‘;
//A
”y1=”<
line1.GetCoordY1()<
//B
”x2=”<
X2<
”y2=”<
y2<
Print();
line2=line1;
//c
line2·
运行程序的结果:
x1=50
y1=60
x2=100
y2=200
该直线的长度为:
=148.661
注意:
1)可用成员选择运算符“·
”来访问对象的公有成员。
2)同类型的对象之间可以整体赋值。
3)对象可用作函数的参数,此时属于值调用;
函数也可以返回一个对象。
4)一个类的对象可作为另一个类的成员,称为对象成员。
classA
{---
};
ClassB{
Aa1,a2;
类B定义了私有成员a1,a2,这两个成员都是类A的对象。
7.1.2.3对象数组和对象指针
1.数组:
采用数组的形式同时定义一组同类型的对象。
对象数组可以为一维,也可以为多维。
定义一维对象数组的方法与定义基本数据类型的方法类似。
格式为:
《存储类型》〈类名〉〈对象数组名〉[〈常量表达法〉];
例:
CDatedates[30];
//定义一个大小为30的CDate类型的数组。
即包含了30个CDate类型的变量。
2.与基本数据类型数组的定义不同,在说明对象数组时,不能对它进行初始化。
对象数组的元素通常是通过默认构造函数进行初始化,因此,一个类能创建对象数组的先决条件是:
它必须具有不带参数或参数全部具有默认值的构造函数,或者没有定义构造函数。
3.指针类型的对象,一般格式:
《存储类型》〈类名〉*〈对象名1〉〈〈,*〈对象名2〉---〉〉;
Cline*line1,*line2;
//指向的数据类型为CLine类型。
可以用new运算符为对象指针分配内存空间。
一般格式
对象指针名>
=new〈类名〉(〈参数表〉)
这里的参数表与相应类中的某个构造函数的参数相对应。
(见10章)
CLine*line3=newCLine;
deleteline3;
对象指针也只能访问封装在其内部的公有成员。
见230。
访问方式与结构类型的指针访问其成员的方式类似,使用运算符“->
”。
格式:
<
->
公有成员函数名>
(<
参数表>
);
对前面定义的对象指针line1
line1->
x2=300;
line2->
y2=400;
line3->
7.1.4*this指针
*this指针是一个指向当前被操作对象的特殊指针。
*this指针可以显示地使用,但很多情况都是隐式使用。
当某个对象调用一个成员函数时,系统将自动为该函数指定一个隐含的参数,该参数是一个指向该对象的指针,这个指针就是*this指针。
*this具有如下形式的默认形式:
*constthis;
.
例7.1.4定义一个时间类。
classCTime
inthours,minutes;
voidSetTime(intnew_hours,intnew_minutes)
hours=new_hours;
minutes=new_minutes;
}
voidGetTime(int&
current_hours,int&
corrent_minutes)
current_hours=hours;
current_minutes=minutes;
}
voidCopyTime(CTime&
Time2);
voidCTime:
CopyTime(CTime&
Time2)
*this=Time2;
//B*this指针代表当前对象
voidmain(void)
inthrs,mins;
CTimeTime1,Time2;
Time1.SetTime(10,30);
Time2.SetTime(12,15);
Time1.GetTime(hrs,mins);
”Timeis:
hrs<
”:
“<
mins<
’\n‘;
Time1.CopyTime(Time2);
Time1.GetTime(hrs,mins);
”aftercopyingTime2toTime1,thetimeis:
”:
’\n‘;
/*
Timeis:
10:
30
aftercopyingTime2toTime1,thetimeis:
12:
15
Pressanykeytocontinue
*/
7.1.2.5类实现数据的封装
面向对象的封装性主要是通过对象的封装性来体现的。
类实现了对数据的封装并不意味着用户不能修改其私有和保护成员数据,这些数据可以通过类的公有成员函数(或类的友元)加以修改。
这些公有的成员函数就称为类的公共接口,它们是类与外界进行信息交换的唯一途径,所有公共接口的集合称为类的协议。
例7.1.5设计一个CbankAccount类,用来模拟银行为客户开一个银行帐号存款并取款的过程。
在取款的函数中设有验证客户银行帐户及其存款数目是否大于取款数目的功能,如果这两个条件不能同时满足,则不能执行取款的操作。
不管是哪一个顾客,他的存取都只是这个类的实例化而已。
(当然,一个真实的银行帐号管理软件远比这复杂)。
这里使用了构造函数,构造函数将在10章介绍。
这里可以将其理解为初始函数。
#include<
classCBankAccount{
CBankAccount()//构造函数
{account=0;
balance=0.0;
voidMakeDeposit(longcount_num,floatamount)//存款第一个参数帐号
account=count_num;
balance+=amount;
cout<
account<
"
\t"
Afterdeposit,thebalanceis:
balance<
endl;
floatWithDraw(longcount_num,floatamount);
//取款
private:
longaccount;
//帐号
floatbalance;
//余额
};
floatCBankAccount:
WithDraw(longcount_num,floatamount)//取款
if(account!
=count_num)//如果输入的帐号不对
Illegalaccount_number!
return0.0;
if(balance<
amount)//如果余额少于取款数额
Theamounttowitndrawisbebyondthebalance:
return0.0:
balance-=amount;
\tAfterwitndraw,thebalanceis:
endl:
returnbalance;
voidmain()
CBankAccounta,b;
//两个对象中的成员数据都为0
a.MakeDeposit(1001,1000);
a.WithDraw(1001,500);
a.MakeDeposit(1001,2000);
a.WithDraw(1001,1000);
b.MakeDeposit(1002,5000);
b.WithDraw(1002,2000);
b.WithDraw(1002,8000);
b.WithDraw(1003,2000);
b.WithDraw(1002,2000);
运行结果:
1001Afterdeposit,thebalanceis:
1000
1001Afterwitndraw,thebalanceis:
500
2500
1001Afterwitndraw,thebalanceis:
1500
1002Afterdeposit,thebalanceis:
5000
1002Afterwitndraw,thebalanceis:
3000
Theamounttowitndrawisbebyondthebalance.
1000
可见,类CbankAccount中的所有成员数据都被封装起来,外部对象不能直接访问它们。
但可以通过公有成员函数MakeDepos