第8章 类和对象的创建Word文档下载推荐.docx
- 文档编号:18750555
- 上传时间:2023-01-01
- 格式:DOCX
- 页数:30
- 大小:27.76KB
第8章 类和对象的创建Word文档下载推荐.docx
《第8章 类和对象的创建Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《第8章 类和对象的创建Word文档下载推荐.docx(30页珍藏版)》请在冰豆网上搜索。
如果在类的内部定义成员函数,该成员函数即被声明为内联函数。
也可以在类中声明,在类外将该成员函数定义为内联函数。
只要在定义前加关键字inline,以显示定义该成员函数为内联函数。
这种函数一般是小的、频繁使用的函数。
内联函数的声明有显式声明和隐式声明两种形式。
隐式声明:
直接将成员函数定义在类内部
显示声明:
将内联函数定义在类外,其声明的形式与在类外定义成员函数的形式类似,但为了使成员函数起到内联函数的作用,在函数声明前要加关键字inline,以显式地声明这是一个内联函数
8.1.2对象的定义和使用
对象的定义
类定义只是定义了一种新的数据类型,只有定义了类的实例即类的对象以后系统才会为该对象分配存储空间。
对象定义可以在类定义的同时直接完成,即在类定义的最后“}”后直接跟对象名列表;
也可以在类定义后要使用该对象时定义。
格式:
类名对象名(参数列表);
说明:
可以同时定义多个对象,之间用逗号隔开。
对象成员的引用
格式:
对象名.数据成员;
对象名.成员函数(实参表);
①在引用成员时要注意访问权限的控制问题。
②对于指向对象的指针在引用其成员时不能使用“.”运算符。
其格式为:
对象名->
数据成员;
成员函数(实参表);
8.2构造函数和析构函数
8.2.1构造函数
构造函数是一种特殊的成员函数,被声明为公有成员,其作用是为类的对象分配内存空间,进行初始化。
关于构造函数有以下几点说明:
①构造函数的名字必须与类的名字相同。
②构造函数没有返回值,不能定义返回类型,包括void型在内。
③对象定义时,编译系统会自动地调用构造函数完成对象内存空间的分配和初始化工作。
④构造函数是类的成员函数,具有一般成员函数的所有性质,可访问类的所有成员,可以是内联函数,可带有参数表,可带有默认的形参值,还可重载。
⑤如果没有定义构造函数,编译系统就自动生成一个缺省的构造函数,这个缺省的构造函数不带任何参数,仅给对象开辟存储空间,不完成对数据成员赋初值。
此时数据成员的值是随机的。
系统自动生成的构造函数的形式为:
类名∷类名()
{
}
8.2.2析构函数
析构函数也是一种特殊的成员函数,也被声明为公有成员,其作用是释放分配给对象的内存空间,并做一些善后工作。
①关于析构函数有以下几点说明:
②析构函数的名字必须是~类名。
③析构函数没有参数、没有返回值、不能重载。
④当对象撤销时,系统会自动调用析构函数完成内存空间的释放和善后工作。
⑤如果没有定义析构函数,系统会自动生成一个缺省的空析构函数。
完成善后工作,其形式为:
类名:
~类名()
对于构造函数和析构函数常见用法是在构造函数中用new动态申请空间,在析构函数中用delete释放内存空间。
8.2.3拷贝构造函数
拷贝构造函数是一个特殊的构造函数,其作用是用一个已经存在的对象初始化本类的新对象。
每个类都有一个拷贝构造函数,它可以是根据用户的需要自定义,也可以由系统自动生成。
拷贝构造函数名与类名相同,但参数是本类对象的引用。
拷贝构造函数没有返回值。
定义拷贝构造函数的格式为:
类名(类名&
对象名)
//函数体
其中,对象名是用来初始化另一个对象的对象的引用。
构造函数只在对象被创建时自动调用,而拷贝构造函数在下列三种情况下会被自动调用:
①用一个对象去初始化本类的另一个对象时。
②函数的形参是类的对象,在进行形参和实参的结合时。
③函数的返回值是类的对象,函数执行完返回时。
8.2.4对象成员
定义对象成员
当用一个类的对象作为另一个类的成员时,该成员称为对象成员。
声明对象成员的一般格式为:
class类名{
类名1对象成员名1;
//需要此类在前面已经定义或声明。
...
};
对象成员的初始化
在类中有对象成员时,创建本类的对象则本类的构造函数要调用其对象成员所在类的构造函数,并采用成员初始化列表对对象成员进行初始化。
这种类的构造函数的定义格式为:
类名∷类名(参数总表):
对象成员1(形参表),...,对象成员n(形参表)
{
//构造函数体
对象成员的构造函数的调用顺序由对象成员在类中的声明顺序决定,与成员初始化列表中的顺序无关。
析构函数的调用顺序正好与构造函数的调用顺序相反。
8.3对象数组与对象指针
8.3.1对象数组
对象数组是指数组中的每个元素都是一个类的对象。
当然这些对象属于同一个类。
定义一维对象数组的一般格式为:
类名数组名[常量表达式];
对象数组的引用
由于对象数组的元素是对象,只能访问其公有成员。
引用格式为:
数组名[下标].公有成员
8.3.2对象指针
对象指针就是对象在内存中的首地址。
指向类类型的指针变量用于存放对象指针。
其定义格式为:
<
类名>
*<
指针变量名>
;
可以在定义的同时对该指针变量进行初始化即用“&
对象名”的形式取出对象首地址赋给该变量,也可以在使用该指针变量时再对它赋值。
8.4静态成员
静态成员是指类中用关键字static说明的那些成员。
静态成员仍然服从访问控制。
8.4.1静态数据成员
静态数据成员是指类中用关键字static说明的那些数据成员。
静态数据成员属于类而不属于某个对象。
它实现同类对象之间的数据共享。
在类中声明静态数据成员时,必须加static说明。
对静态数据成员初始化只能在类外进行,一般在在类声明与main()之间的位置。
格式为:
数据类型类名∷静态数据成员名=值;
对静态数据成员的引用可以有两种形式:
类名∷静态数据成员
对象名.静态数据成员
8.4.2静态成员函数
静态成员函数是指类中用关键字static说明的那些成员函数。
可以用静态成员函数在未建立任何对象之前去处理静态数据成员。
静态成员函数只能直接引用该类的静态数据成员和静态成员函数,不能直接引用非静态数据成员。
调用静态的两种形式:
类名∷静态函数名();
或对象名.静态函数名();
8.5友元
C++引入了友元实现了在类的外部访问类的私有成员的功能。
这样,即不放弃私有数据的安全性,又可在类的外部访问类的私有成员。
但一定程度上说友元破坏了类的封装性,在使用友元时一定要慎重。
友元关系是单向的,也是不能传递的。
8.5.1友元函数
一个普通函数作为某个类的友元时即为友元函数。
在该函数中可以访问其由friend声明语句所在的类的对象的私有成员和公有成员。
在类中作如下声明,则说明该函数不是本类的成员函数,而是友元函数。
friend函数类型友元函数名(参数表);
友元函数的定义可以在类内也可以在类外,在类外定义时不需要加类名和普通函数定义没有区别。
通常友元函数的定义在类外进行。
友元函数不是类的成员,因而不能直接引用对象成员的名字,也不能通过this指针引用对象的成员,必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员。
为此,友元函数一般都带有一个该类的入口参数。
8.5.2友元成员函数
某个类的成员函数作为另一个类的友元即为友元成员函数。
通过友元成员函数,可以访问由friend声明语句所在的类的对象的私有成员和公有成员。
当一个类A的成员函数作为另一个类B的友元函数时,在类B中的声明格式为:
friend函数类型成员函数所在类类名:
函数名(参数表);
8.5.3友类
当一个类作为另一个类的友元时即为友类。
若类A是类B的友类,则类A中的所有成员函数都是类B的友元成员函数,所以可以通过对象名访问B的私有成员和公有成员。
当类A为类B的友类时,在类B中的声明格式为:
firiendclass<
友元类名>
或friend<
【典型例题】
例题1.下列程序段是否有错,若有错请改错。
#include<
iostream.h>
classpoint---------------------------------------------①
intx,y;
voidsetpoint(int,int);
--------------------②
intpoint:
setpoint(intxx,intyy)----------------③
x=xx;
---------------------------------------------④
y=yy;
---------------------------------------------⑤
return1;
------------------------------------------⑥
voidmain()
pointp1;
------------------------------------------------------------------------------⑦
p1.setpoint(2,4);
---------------------------------------------------------------------⑧
cout<
<
”坐标为:
(”<
p1.x<
”,”<
p1.y<
”)”<
endl;
-------------------------⑨
解答:
这里⑨错误,不能在类定义以外直接访问类的私有成员。
要得该点的两个坐标,应该在类中定义获取私有成员x,y的公有成员函数,使得可以在类外通过类的公有成员函数对其私有成员进行间接访问。
所以程序应改为:
classpoint
//声明成员函数setpoint()的函数原型
intgetx();
//声明成员函数getx()的函数原型
intgety();
//声明成员函数gety的函数原型
voidpoint:
setpoint(intxx,intyy)//定义成员函数setpoint()
intpoint:
getx()//定义成员函数getx()
{returnx;
gety()//定义成员函数gety
{returny;
例题2.在下列函数原型中,可以作为类student的构造函数的说明的是()。
(a)voidstudent(intage);
(b)intstudent();
(c)student(int)const;
(d)student(int);
本题主要考查对构造函数的特点的掌握。
构造函数的名字必须与类的名字相同。
构造函数没有返回值,不能定义返回类型,包括void型在内。
构造函数可以是内联函数,可带有参数表,可带有默认的形参值,还可重载。
选项a、b均有返回值类型,不能作为构造函数。
选项c为常成员函数,构造函数不能为常成员函数。
答案为:
d
例题3.下列说法正确的是()。
(a)可以定义修改对象数据成员的const成员函数。
(b)不允许任何成员函数调用const对象,除非该成员函数也声明为const。
(c)const对象可以调用非const成员函数。
(d)const成员函数可以调用本类的非const成员函数。
c++编译器不允许任何成员函数调用const对象,除非该成员函数本身也声明为const。
声明const的成员函数不能修改对象,因为编译器不允许其修改对象。
对const对象调用非const成员函数是个语法错误。
定义调用同一类实例的非const成员函数的const成员函数是个语法错误。
b
例题4.运行下列程序后,”constructingA!
”和”destructingA!
”分别输出几次()。
classA
intx;
public:
A()
{cout<
"
constructingA!
~A()
"
Aa[2];
A*p=newA;
deletep;
(a)2次,2次(b)3次,3次(c)1次,3次(d)3次,1次
本题主要考查在什么情况下系统会调用构造函数与析构函数。
在主函数中定义了一个对象数组,其中有两个元素,该数组中的每个元素都是一个类的对象,所以这里会调用2次构造函数;
newA时创建一个A类的对象,所以也会调用构造函数,因此一共调用3次构造函数。
deletep;
会撤消new运算分配的空间,它会调用1次析构函数。
主函数结束时要释放数组所占空间,会调用2次析构函数,因此析构函数也调用了3次。
例题5.运行下列程序的结果为__________________________。
string.h>
classcourse
intid;
charname[50];
course(intcsid,char*csname)
cout<
constructingcourse!
id=csid;
strcpy(name,csname);
~course()
destructingcourse!
intgetid()
{returnid;
char*getname()
returnname;
classstudent
charname[10];
intage;
coursec1;
student(char*sname,intsage,intcid,char*cname):
c1(cid,cname)
constructingstudent!
strcpy(name,sname);
age=sage;
~student()
destructingstudent!
voidprints()
name:
name<
endl
<
age:
age<
courseid:
c1.getid()<
coursename:
c1.getname()<
studentst1("
tom"
23,1,"
c++programminglanguage"
);
st1.prints();
本题主要考查在为含有对象成员的类创建对象时,构造函数的调用顺序,对象成员的初始化问题以及对象撤消时调用析构函数的顺序。
对于本程序,在主函数中创建student类的对象则调用其构造函数student(),该构造启动时,首先为数据成员分配空间,然后根据在类中声明的对象成员的顺序依次调用其构造函数,在这里调用course类的构造函数,最后才执行自己的构造函数的函数体。
析构函数以调用构造函数相反的顺序被调用。
tom
23
1
c++programminglanguage
例题6.运行下列程序输出结果为_____________________。
classA{
A(intX){cout<
ok!
A(){}
intmain()
Aa[3],a1(3);
return0;
本题主要考查对重载构造函数的理解。
这里创建对象数组时,对数组的每一个元素都将调用一次构造函数,如果没有显式给出数组元素的初值,则调用缺省构造函数。
而创建对象a1时带有一个整型参数,所以调用以整型作为参数的构造函数,它输出ok!
。
所以,本题答案为:
ok!
例题7.运行下列程序结果为________________________。
constdoublePI=3.14159;
classcircle
doubler;
staticintnum;
circle(double);
circle(circle&
doublegetr();
circle:
circle(doublei)
r=i;
circle(circle&
c)
num++;
第"
num<
次调用拷贝构造函数!
r=c.r*num;
doublecircle:
getr()
returnr;
doublegetradius(circlec3)
returnc3.getr();
circlefun1()
circlec4(5);
returnc4;
intcircle:
num=0;
circlec1
(1);
c1:
c1.getr()<
circlec2(c1);
c2:
c2.getr()<
c3:
getradius(c1)<
circlec4
(1);
c4=fun1();
c4:
c4.getr()<
本题主要考查在什么情况下会调用拷贝构造函数。
本题答案为:
第1次调用拷贝构造函数!
第2次调用拷贝构造函数!
2
第3次调用拷贝构造函数!
15
例题8.读程序写结果或者程序填空。
constinti;
int&
j;
A(int&
var):
i(10),j(var)
{}
voidshow()
i:
i<
j:
j<
intx=1;
Aa1(x);
a1.show();
本题主要考查对符号常量和引用的理解。
常量是不能被赋值的,一旦初始化后,其值就永不改变,引用变量也是不可重新指派的,初始化后,其值就固定不变了。
结果为:
10
例题9.运行下列程序结果为__________________。
classObj{
staticinti;
Obj(){i++;
~Obj(){i--;
staticintgetVal(){returni;
intObj:
i=0;
voidf(){Objob2;
cout<
ob2.getVal();
intmain(){
Objob1;
f();
Obj*ob3=newObj;
ob3->
getVal();
deleteob3;
Obj:
本题主要考查对静态数据成员的理解。
在主函数中创建对象ob1则调用该类的构造函数,使得静态数据成员加1,为1;
接着调用函数f(),在函数中创建对象ob2,这时再次调用构造函数,使得静态成员的值为2,ob2.getVal()返回静态数据成员i的值,即输出2。
函数f()结束,则ob2的生存期结束,自动调用其析构函数使静态数据成员i的值变为1。
接着在主函数中用new运算符动态分配存储空间,又一次调用构造函数使i加1,所以再次输出时i的值为2。
最后用delete释放ob3所指的对象空间,则会调用析构函数使i的值减1,因此输出i的值为1。
221
例题10.若类A是类B的友元,类B是类C的友元,则下列说法正确的是()。
(a)类B是类C的友元(b)类A是类C的友元
(c)类A,B,C互为友元(d)以上说法都不对
本题考查对友元关系的理解。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第8章 类和对象的创建 对象 创建