c++程序设计谭浩强第9章_第1页
c++程序设计谭浩强第9章_第2页
c++程序设计谭浩强第9章_第3页
c++程序设计谭浩强第9章_第4页
c++程序设计谭浩强第9章_第5页
已阅读5页,还剩99页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第九章关于类和对象的进一步讨论

9.1构造函数

9.2析构函数

9.3调用构造函数和析构函数的顺序

9.4对象数组

9.5对象指针

9.6共用数据的保护

9.7对象的动态建立和释放

9.8对象的赋值和复制

9.9静态成员

9.10友元

9.11类模板

9.1构造函数

所谓构造函数用于实现对对象的初始化操作;

一、对象的初始化(P263)

1.为什么要对对象进行初始化

classstu

{intnum;

stringname;

};

stustu1,stu2;

问题:

一个对象在声明时,系统为其分配存储空间中数据成员是否有确定的值;

2.类的数据成员是否可以在类声明的同时为其初始化

二、构造函数的作用

构造函数是-种特殊的成员函数,其作用是:为新创建的对象分配空间,或为

对象的数据成员初始化。构造函数是由用户定义的,他必须与类名同名,以便系统能识

别他并把他们作为构造函数(注意:当在类中用户没有定义构造函数时,系统将给出默认的构造函数)。

1.构造函数的声明

例9.1P264在例8.3的基础上定义构造函数

#include<iostream>

usingnamespacestd;

classTime

{public:

Time(inthjntm,ints)〃构造函数

{hour=h;

minute=m;

sec=s;

}

voidset_time();

voidshow_time();

private:

inthour;

intminute;

intsec;

};

voidTime::set_time()

{cin»hour;

cin»minute;

cin»sec;

}

voidTime::show_time()

{cout«hour«'':''«minute«'':''«sec«endl;

intmain()

{Time"(10,10,10);

tl.show_time();

Timet2(20,20,20);

t2.show_time();

return0;

}

说明:

在建立Time类的对象时,自动执行构造函数Time。,使该类中的所有对象中的各数据成员赋初值0。

2.构造函数的特点

•构造函数是一个特殊的成员函数,该函数的名字与类名相同;

•构造函数的功能是给对象初始化;

•构造函数的函数体可写在类体内,也可写在类体外;

•构造函数可以带参数,也可以不带参数;

•程序中不能直接调用构造函数,在创建时由系统自动调用构造函

数,构造函数一般声明为public;

•构造函数不允许有返回值,也不允许定义构造函数的返回值类型,

其中包括void类型;

•如果用户没有自定义构造函数,则系统自动一个缺省的构造函数,

而该缺省的构造函数,不执行初始化操作。

例9・1'将构造函数在类内声明,在类外定义

#include<iostream>

usingnamespacestd;

classTime

{public:

Time();〃构造函数声明

voidshow_time();

private:

inthour;

intminute;

intsec;

};

Time::Time()〃构造函数定义

{hour=0;

minute=0;

sec=O;

}

voidTime::show_time()

{cout«hour«n:n«minute«H:n«sec«endl;

}

intmain()

{Timetl;

tl.show_time();

Timet2;

t2.show_time();

return0;

带参数的构造函数(P266)

目的:实现对不同的对象的数据成员进行不同的初始化。

带参数构造函数首部的一般形式为:

构造函数名(类型1形参1,类型2形参2,。。。。。)

用带参构造函数直接创建对象一般形式为:

类名对象名(实参1,实参2,。。。。。。)

例9.2有两个长方柱体,其长、宽、高分别为:(1)12,25,

30;(2)15,30,21o要求:分别求他们的体积。

问题分析:

长方柱体具有的共同属性:长(he)、宽(wi)、高(le);

长方柱体积计算:he*wi*le用成员函数实现;

#include<iostream>

usingnamespacestd;

classBox

{public:

Box(int,int,int);〃带参的构造函数声明

intvolumeQ;

private:

inthe;

intwi;

intle;

};

Box::Box(inth,intw,intlen)〃类外定义构造函数

{he=h;

wi=w;

le=len;

)

intBox::volume()

{return(he*wi^le);}

intmain()

{Boxboxl(12,25,30);

cout«HThevolumeofboxlisH«boxl.volume()«endl;

Boxbox2(15,30,21);

cout«HThevolumeofbox2isH«box2.volume()«endl;

return0;

)

例3.3比较构造函数与普通成员函数的调用

#include<iostream>

usingnamespacestd;

classDate

{public:

Date(inty,intm,intd):year(y),month(m),day(d)

{);〃构造声明函数

voidsetDate(inty,intm,intd);

voidshowDate();

private:

intyear,month,day;

);

voidDate::setDate(inty,intm,intd)〃普通成员函数实现

{year=y;

month=m;

day=d;

);

inlinevoidDate::showDate()

{cout«year«,,.,,«month«,,.n«day«endl;

)

voidmain()

{Datedatel(1998,4,28);〃定义类Date的对象datel,自动调用构

造函数,初始化对象datel

cout«HDateloutputl:H«endl;

datel.showDateO;

datel.setDate(2002,ll,14);

cout«HDateloutput!:H«endl;

datel.showDateO;

}运行结果:

onstructing.

ateloutputl:

998.4.28

ateloutput2:

002.11.14

ressanykeytocontinue

说明:构造函数是在对象定义时由系统自动调用(这是构造函数与普通成员函数的最大区别)

四、用参数初始化表对数据成员初始化

当需要初始化的数据成员较多时,允许采用更为简洁的一种带用参数初始化表形式的构造函数对数据

成员初始化。

1.带有数据成员初始化表的构造函数的一般形式:

类名::构造函数名(参数表):数据成员名1(初始值1),数据成员名2(初始值2)……

构造函数体

}

例:9.4设计一个长方体类,用他计算不同长方体的表面积和

体积。

问题分析:

(1)在这个类Box中必须有3个私有数据:长、宽、高(分

别用a、b、c表不);

(2)采用构造函数Box(inti,intj,intk)实现初始化

计算体积getvohime()、表面积getarea()的成员函数。

#include<iostream>

usingnamespacestd;

classBox

{private:

inta,b,c;

intgetvolume()〃计算体积

{returna*b*c;}

intgetarea()〃计算面积

{return2*(a*b+b*c+c*a);}

public:

Box(inti,intj,intk):a(i),b(j),c(k)〃带有数据成员初始化表的构造函数

{}〃构造函数体

voiddisplayO

{cout«a«^“vvbvv»u«c«endl;

coutvv”长方体的表面积为:”《getarea()vven祖;

cout«H体积为:**«getvolume()«endl;

)

};

intmain()

{BoxA(2,3,4),B(10,20,30);

A.display();

B.displayO;

return0;

}

其中:构造函数

Box(inti,intj,intk):a(i),b(j),c(k)

()

也可写成:

Box(inti,intj,intk)

{a=i;b=j;c=k;}

2.说明:

(1)对于数组类型的数据成员初始化,只能在构造函数体中

通过赋值方式初始化;

例如:

classC

{public:

C(intI,intJ,charN[]):i(I),j(J)

{strcpy(name,N);}

private:

inti;

intj;

charname[25];

}

(2)数据成员初始化表中数据成员的顺序要与其在类里声明

的顺序一致。

五、构造函数的重载(P267)

构造函数重载的意义在于:对同一个类的不同对象提供不

同的初始化方法。

例9.5重载构造函数应用

#include<iostream>

usingnamespacestd;

classDate

{public:

Date();〃无参的构造函数声明

Date(inty,intm,intd);〃有参的构造函数声明

voidshowDate();

private:

intyear;

intmonth;

intday;

};

Date::Date()〃无参的构造函数实现

{year=1998;

month=4;

day=28;

}

Date::Date(inty,intm,intd)〃有参的构造函数实现

{year=y;

month=m;

day=d;

}

inlinevoidDate::showDate()

{cout«year«n.n«month«n.n«day«endl;

}

intmain()

{Datedatel;

cout«nDateloutput:n«endl;

datel.showDateQ;

Datedate2(2002,H,14);

cout«nDate2output:n«endl;

date2.showDate();

return0;

}

运行结果:

ateloutput:

998.4.28

ate2output:

002.11.14

ressanykeytocontinue

说明:(P269)

(1)一个类中的无参构造函数只能有一个。系统提供的缺省构造函数与用户自定义的无参构造函数的区

别在于:系统提供的缺省构造函数的函数体是空的;

(2)选用无参的构造函数为对象初始化时,是无需任何说明。

(3)一个类中无论重载多少个构造函数,当一个对象在建立时,由系统自动只调用其中的一个构造函数。

六、使用默认参数的构造函数(P269)

提供一种方便、灵活的为对象初始化的方式。

例9.6(P269)例9.4

#include<iostream>

usingnamespacestd;

classBox

{public:

Box(intw=10,inth=10,intlen=10);〃声明构造函数时指定默认参数

intvolume();

private:

intheight;

intwidth;

intlength;

};

Box::Box(intw,inth,intlen)

{height=h;width=w;length=len;

)

intBox::volume()

{return(height*width*length);}

intmain()

(

Boxboxl;

cout«HThevolumeofboxlisH«boxl.volume()«endl;

Boxbox2(15);

cout«HThevolumeofbox2isH«box2.volume()«endl;

Boxbox3(15,30);

cout«HThevolumeofbox3isH«box3.volume()«endl;

Boxbox4(15,30,20);

cout«HThevolumeofbox4isH«box4.volume()«endl;

return0;

}

说明:(P271)

(1)默认参数值要在构造函数声明时给出;

(2)在带有默认参数值构造函数声明时,形参名可以省略;

例如:Box(int=10,int=10,int=10);

注意:保持其顺序。

(3)避免同时使用重载和带默认参数的构造函数,有可能产生二义性。

9.2析构函数(P272)

所谓析构函数:当一个对象完成任务之后,在释放给这个对象所分配的内存空间之前完成一些清理工作。

1.析构函数的一般形式为:

class类名

{public:

〜类名(){}〃析构函数

);

2.析构函数的特点

•析构函数由系统自动调用;

•析构函数名:在类的名字前面加

•析构函数没有参数,也没有返回值;

•一个类中只可以定义一个析构函数(不允许重载);

•如果类中没有声明析构函数,C++编译程序将自动生成一个缺省的析构函数。

例9.7(P272)例9.5包含构造函数与析构函数的C++程序

#include<iostream>

#include<string>

usingnamespacestd;

classStudent

{public:

Student(intn,stringnam,chars)〃构造函数

{num=n;

name=nam;

sex=s;

cout«”构造函数调用."«endl;

}

〜Student。〃析构函数

{coutvv”析构函数调用Jvvendl;

voiddisplayO

{cout«''num:n«num«endl;

cout«''name:''«name«endl;

cout«"sex:''<<sex«endl«endl;

}

private:

intnum;

stringname;

charsex;

};

intmain()

{Studentstudl(10010;,WangJi,\T);

studl.displayO;

Studentstud2(10011,nZhang_funn/m,);

stud2.display();

return0;

构造函数调用.

nu.ni:10010

name:IJan9_1i

sex=£

构造函数调用.

numi1001X

name二Zhang_fun

sex:m

Pi*essanykeytocontzxnue

3.析构函数被系统自动执行的前提条件

•一个局部对象在所在函数调用结束时,该局部对象释放之前系统自动执行析构函数;

•static局部对象在main函数结束或调用exit函数结束程序时,该static局部对象释放之前系统自动执

行析构函数;

•全局对象在其生命周期结束时,该全局对象释放之前系统自动执行析构函数;

•用new运算符动态建立的对象,当用delete运算符释放该对象时,系统自动执行析构函数。

9.3调用构造函数与析构函数的顺序(P274)

一般情况下,调用析构函数的顺序与创造对象的顺序刚好相反(对同一类存储类别的对象)。

先构造的后析构,后构造的先析构。

查看P274图9.1

例9.8|分析如下程序

#include<iostream>

usingnamespacestd;

classperson

{private:

inti;

public:

person(intid);//构造函数声明

〜person。;//析构函数声明

voidprint();

};

voidperson::print()

{cout«i«endl;}

person::person(iiitid)〃构造函数实现

{i=id;

cout«n\nperson对象”vvivv"仓U建"vvendl;

person::-person()〃析构函数实现

{cout«n\nperson对象”vvivv"撤销"vvendl;}

intmain()

{personx(l),y(2);

cout«npersonobjectx.in;

x.print();

cout«npersonobjecty・i'';

y.print();

return0;

}

运行结果:

ei*son对象1仓u建

ei*son又才^^2仓

eonobjectx.±X

eonobject-±2

e>*son^.2

ei*son对象工撤销

i*essanykeytocootini,ie-

关于构造函数与析构函数的调用:

P275⑴⑵⑶

9.4对象数组

所谓对象数组是指:

每一数组元素都是同一类对象的数组。

引入对象数组意义:有规律的处理属于同一类的一批属性相同的对象。

classStudent

{private:

intnum;

stringname;

floatengscore,chiscore,matscore;

public:

voidset();

voiddisp();

);

Studentstu[5];

numnameengscorechiscorematscore

stu[0]

stu[l]

stu[2]

stu[3]

stu[4]

一、对象数组的定义格式:

类名数组名[下标表达式];

例9.9简单对象数组的引用

#include<iostream>

usingnamespacestd;

classex

{public:

voidset_x(intn)

{x=n;}

intget_x()

{returnx;}

private:

intx;

);

intmain()

{exob[4];

inti;

for(i=0;i<4;i++)

ob[i].set_x(i);

for(i=0;i<4;i++)

cout«ob[i].get_x()«nn;

cout«endl;

return0;

123

ressanykeytocontinue

二、为对象数组元素初始化的自定义构造函数

•当各个元素对象的初值要求为相同的值时,应该在类中定义不带参数的构造函数或带有缺省参数值的

构造函数;

•当各个元素对象的初值要求为不同的值时,应该在类中定义带参数的构造函数。

例9.10通过初始化表给对象数组赋值。

#include<iostream>

usingnamespacestd;

classex

{public:

ex()〃无参的构造函数

{x=123;}

ex(intn)〃有参的构造函数

{x=n;}

intget_x()

{returnx;}

private:

intx;

);

intmain()

{exobl[4]={ll,22,33,44);〃调用有参的构造函数

exob2[4]={55,66);〃ob⑵,ob[3]调用无参的构造函数

exob3[4]={ex(ll),ex(22),ex(33),ex(44)};

exob4[4]={ex(55),ex(66));

ob4[2]=ex(77);

ob4[3]=ex(88);

inti;

for(i=0;i<4;i++)

cout«obl[i].get_x()«nn;

cout«endl;

for(i=0;i<4;i++)

cout«ob2[i].get_x()«nn;

cout«endl;

for(i=0;i<4;i++)

cout«ob3[i].get_x()«nn;

cout«endl;

for(i=0;i<4;i++)

cout«ob4[i].get_x()«nn;

cout«endl;

return0;

}

1223344

566123123

1223344

5667788

ressanykeytocontinue

例9.11构造函数具有一个以上的参数。P276例9.6

#include<iostream>

usingnamespacestd;

classBox

{public:

Box(inth=10,intw=12,intlen=15):

height(h),width(w),length(len){}

intvolume();

private:

intheight;

intwidth;

intlength;

);

intBox::volume()

{return(height*width*length);}

intmain()

{BOXa[3]={Box(10,12,15),Box(15,18,20),Box(16,20,26)};

cout«nvolumeofa[0]isn«a[0].volume()«endl;

cout«nvolumeofa[0]isH«a[l].volume()«endl;

cout«Hvolumeofa[0]isH«a[2].volume()«endl;

return0;

)

问题:采用如下的对象数组定义初始化方式,其结果如何?

(1)Boxa[3]={Box(),Box(15,18,20),Box(16,20,26)};

(2)Boxa[3]={Box(15,18,20),Box(16,20,26)};

9.5对象指针(P277)

一、指向对象的指针

对象指针即是指:用于存放对象地址的变量。

声明对象指针的一般形式为:

类名*对象指针名;

1.用指针访问单个对象成员

例9.12对象指针的使用

#include<iostream>

usingnamespacestd;

classexe

{public:

voidset_a(inta)

{x=a;}

voidshow_a()

{cout«x«endl;}

private:

intx;

};

intmain()

{exeob,*p=&ob;

ob.set_a(2);

p->show_a();

return0;

}

2.用对象指针访问对象数组

对象数组名代表对象数组的首地址。

例9.13分析如下程序

#include<iostream>

usingnamespacestd;

classex

{public:

ex(intn,intm)〃构造函数

{x=n;y=m;}

voiddisp()

nn

{cout«x«,«y«endl;}

private:

intx,y;

};

main()

{exop[4]={ex(l,2),ex(3,4)9ex(5,6),ex(798));

ex*p=&op[3];

for(inti=0;i<4;i++)

{p->disp();

P-;

)

return0;

)

7,8

5/6

3.4

1.2

Pressanykeytocontinue

二、指向对象成员的指针(P278)

存放对象成员地址的指针变量就是指向对象成员的指针。

L指向对象数据成员的指针

声明指向对象公用数据成员指针变量的一般形式为:

数据类型名*指针变量名;

例914分析如下程序

#include<iostream>

usingnamespacestd;

classex

{public:

intx;

ex(intxl=10)〃带有默认参数的构造函数

{x=xl;}

);

intmain()

{exT;

int*p=&T.x;//X是公有数据成员

cout«*p«endl;

return0;

)

2.指向对象成员函数的指针

定义指向对象成员函数指针的目的:通过该指针可实现对成员函数的调用。

声明指向对象公用成员函数指针变量的一般形式为:

数据类型名(类名::*指针变量名)(参数表列);

定义一个指向对象成员函数指针变量指向一个公用成员函数的一般形式为:

指针变量名二&类名::成员函数名;

其功能:将指定的成员函数入口地址赋值给该指针变量。

例9.15p279例9.7有关对象指针的使用方法

#include<iostream>

usingnamespacestd;

classTime

{public:

Time(int?int9int);〃声明构造函数

inthour;

intminute;

intsec;

voidget_time();〃声明公有成员函数

};

Time::Time(inth9intm,ints)〃定义构造函数

{hour=h;

mmute=m;

sec=s;

}

voidTime::get_time()〃定义公有成员函数

{cout«hour«n:n«minute«n:n«sec«endl;

)

intmain()

{Time"(10,13,56);〃定义对象ti

int*pl=&tl.hour;〃定义指向对象数据成员的指针变量pi

cout«*pl«endl;〃通过pi调用对象的数据成员

tl.get_time();

Time*p2=&tl;〃定义指向对象tl的指针变量p2

〃通过调用对象的成员函数

p2->get_time();P2tl

void(Time::*p3)();〃定义指向对象成员函数的指针变量p3

p3=&Time::get_time;〃定义指针变量p3指向Time类的成员函数get_time

(tl.*p3)();〃对象tl通过p3调用成员函数get_time,相当于tl.get_time()

return0;

)

三、this指针(P281)

每一个成员函数中都包含有一个称为this的特殊指针,其值为当前所调用的成员函数所在对象的起始

地址。通过this指针的指向,可使得不同的对象调用同一段成员函数代码,得到不同的结果。

例9.16显示this指针的值

#include<iostream>

usingnamespacestd;

classA

{public:

A(intxl)〃构造函数

{x=xl;}

voiddisp()

{cout«Hthis=H«this«Hwhenx=H«this->x«endl;}

private:

intx;

);

intmain()

{Aa(l),b(2),c(3);

a.dispO;

b.dispO;

c.dispO;

return0;

)

this=0X0012FF7Cwhenx=l

this=0X0012FF78whenx=2

tnis=0X0012FF74whenx=3

Pressanykeytocontinue.

例9.17分析如下程序,理解this和*this的用法

(*略*)

#include<iostream>

usingnamespacestd;

classSp

{intx,y;

public:

Sp(inti=0,intj=0)〃带有缺省值的构造函数

{x=i;y=j;}

voidcopy(Sp&xy);〃形参是对象引用的成员函数

voidprint()

{cout«x«n/f«y«endl;}

);

voidSp::copy(Sp&xy)

{if(this==&xy)return;

*this=xy;

)

voidmain()

{Sppl,p2(5,6);

pl.print();

pl.copy(p2);〃等价于pl=p2

pl.print();

}

L0

「6

iessanykeytocontinue

说明:

this中的对象pl的指针,比较判断对象pl的地址是否与&xy相等,如果相等就不再拷贝,否则将实

参给定的对象值赋给对象pl,于是对象pl获取了对象P2的值。

9.6共用数据的保护(p282)

通过const的定义,使得要处理的数据,既可以在一定范围内共享,又保证它不被任意的修改。

一、常对象

常对象是指:在说明对象时用const修饰的对象。常对象的数据

成员值在对象的整个生存期不能被修改。

常对象的说明形式为:

类名const对象名[(参数表)];

□V•

const类名对象名[(参数表)];

注:常对象在定义时必须进行初始化,而且不能被更新。

例9.18非常对象与常对象的比较

#include<iostream>

usingnamespacestd;

classsamp

{public:

intm;

samp(inti,intj)〃构造函数

{m=i;n=j;}

voidset(inti)

{n=i;}

voiddisp()

{cout«/,m=,,«m«endl;

cout<<〃n=〃<<n<〈endl;

private:

intn;

);

intmain()

{sampa(10,20);

a.set(40);

a.m=30;

a.disp();

return0;

i=30

=40

iessanykeytocontinue

说明:

若将sampa(10,20);改为:constsampa(10,20);则出现3个错误,语句2,3的错误指出,C++不允

许直接或间接地更改常对象的数据成员。语句4的错误指出,C++不允许常对象调用普通的成员函数。(常

对象只能调用它的常成员函数。)

二、常对象成员

1.常数据成员

常数据成员是指:在说明数据成员时用const修饰。常数据成员只

能通过构造函数的参数初始化表对其进行初始化,而其它函数

都不能对该成员赋值。

例9.19常数据成员

#include<iostream>

usingnamespacestd;

classdate

{public:

date(inty,intm,intd);

voidshow();

//voidset(inty,intm,intd)error

//{year=y;month=m;day=d;}

private:

constintyear;

constintmonth;

constintday;

);

date::date(inty,intm,intd):

year(y),month(m),day(d)

inlinevoiddate::show()

{cout«year«H."«month«n.n«day«endl;

}

intmain()

{datedatel(1998,4,28);

datel.showQ;

return0;

)

2.常成员函数

常成员函数是指:在说明成员函数时用const修饰。

常成员函数的说明格式如下:

类型说明符函数名(参数表)const;

例9.20常成员函数的应用

#include<iostream>

usingnamespacestd;

classdate

{public:

date(inty,intm,intd);

voidshow();

voidshow()const;〃常成员函数重载

private:

intyear,month,day;

);

date::date(inty,intm,intd):

year(y),month(m),day(d)

()

voiddate::show()

{cout«"show1:"«endl;

cout«year«,,."«month«,,.n«day«endl;

)

voiddate::show()const

{cout«Hshow2:H«endl;

cout«year«,,.,,«month«,,.,,«day«endl;

)

intmain()

{datedatel(1998,4,28);

datel.showQ;

constdatedate2(2002,11,14);

date2.show();

return0;

^howl:

L998.4.28

>how2:

>002.11.14

>ressanykeytocontinue

说明:

(1)如果将一个对象说明为常对象,则通过该对象只能调用它的常成

员函数,而不能调用普通的成员函数;

(2)常成员函数不能更新对象的数据成员,也不能调用该类中的普通

成员函数。

仔细阅读P91说明(1)(2)(3)以及P90表3.1

三、指向对象的常指针

所谓常指针是指:在函数的执行过程中,指针的指向是不允许被改

变。而指向对象的常指针即指其指针变量始终指向一个对象。

定义指向对象的常指针的一般形式为:

类名*const指针变量名二对象地址;

例如:

Timetl(10,2,5);

Time*constpt=&t1;

说明:

(i)指向对象的常指针变量的值不能被改变,但其所指对象中的数据成员的值可以被改变;

(2)常指针通常用作函数的形参,以防止在函数的执行过程中被误操作修改其指针变量的值。

四、指向常对象的指针变量

1.指向常变量的指针变量

定义指向常变量的指针变量的一般形式:

const类型名*指针变量名;

例如:

constcharch='a';

constchar*p=&ch;

说明:

(1)如果一个变量已被声明为常变量,则只能用指向常变量

的指针变量指向它;

例如:

constcharc[]="boy”;

constchar*pl=c;〃冰

char*p2=c;//error

(2)指向常变量的指针变量也可以指向一个非const变量,即

可以通过该指针变量访问该变量,但不可改变该变量的值;

例如:

charch='a';

constchar*p=&ch;

*p='b';//error

ch二'b';//ok

(3)如果函数的形参是指向非const型变量的指针,则实参只

能用指向非const型变量的指针,而不能用指向const型变量

的指针。

例如:

constcharstr口二“boy”;

voidfun(char*ptr);

fun(str);//error,试图让一个普通的指针变量指向一个const类型的数组,与说明(1)茅盾。

2.指向常对象的指针变量

定义指向常对象的指针变量的一般形式:

const类名*指针变量名;

说明:

(1)如果一个对象已被声明为常对象,则只能用指向常对象的指针变

量指向它;

例如:

Timeconst”(10,12,15);〃声明ti为常对象

constTime*p=&tl;〃冰

Time*p2=&tl;//error

(2)如果定义了一个指向常对象的指针变量,并使它指向一个非const

对象,则其指向的对象是不可以通过该指针来改变.

例如:

Time”(10,12,15);〃声明非const对象tl

constTime*p=&tl;〃水

tl.hour=18;//ok

(*p).hour=18;//error

(3)指向常对象的指针变量通常用于函数的形参,以用来保护形参指

针所指向的对象在函数执行过程中不被修改;

(4)一个指向常对象的指针变量,是不能通过它改变所指向的对象的

值,但指针变量本身的值是可以改变的,即其指向是可以被改变的。

例如:

Timeconst”(10,12,15);〃声明tl为常对象

Timeconstt2(8,12,15);〃声明t2为常对象

constTime*p=&tl;//ok

p=&t2;//ok

五、对象的常引用

引用即为别名,对象的引用即为对象的别名,而对象的常引用是该别名具有const属

性,即指不能通过该引用对对象的数据进行修改。

对象的常引用通常用作函数的参数,其目的在于在整个函数的执行过程中,数据不能被任意的修改。

例9.21p289例9.8对象的常引用

#include<iostream>

usingnamespacestd;

classTime

{public:

Time(int,int,int);〃构造函数

inthour;

intminute;

intsec;

);

Time::Time(inth,intm,ints)

{hour=h;

minute=m;

sec=s;

)

voidfun(Time&t)〃普通的外部函数

{t.hour=18;}

intmain()

{Timetl(10,13,56);

fun(tl);

cout«tl.hour«endl;

return0;

)

六、const型数据小结(P290)

阅读表9.3

9.7对象的动态建立和释放

对象动态建立和释放的目的:提高内存空间的利用率。

对象动态建立的一般语法形式为:(通过指针和new来实现)

类名*指针变量;〃定义对象指针

指针变量二new类名;〃动态分配空间

或:类名*指针变量=new类名;

C++允许在执行new时,利用构造函数对新创建对象初始化:

一般语法形式为:

类名*指针变量=new类名[(实参表)];

例9.22通过指针和new来实现

#include<iostream>

usingnamespacestd;

classDate

{public:

Date(inty,intm,intd);

voidsetDate(inty,intm,intd);

voidshowDate();

private:

intyear;

intmonth;

intday;

);

Date::Date(inty,intm,intd):

year(y),month(m),day(d)

()

voidDate::setDate(inty,intm,intd)

{year=y;month=m;day=d;}

voidDate::showDate()

{cout«year«''・''«month«''・''«day«endl;

)

voidmain()

{Date*datel;〃定义Date类型的指针对象

datel=newDate(1998,4,28);〃通过指针datel和new,自动调用构造函数,初始化对

象datel

cout«nDateloutputl:n«endl;

datel->showDate();

datel->setDate(2002,ll?14);

cout«HDateloutput2:n«endl;

datel->showDate();

Dateloutputl:

1998.4.28

Dateloutput2:

2002.11.14

Pressanykeytocontinue

对象释放动态建立的一般语法形式为:

delete对象指针变量;

注:在执行delete时,在释放内存空间之前,系统自动调用析构函数,完成有关的善后清理工作。

9.8对象的赋值和复制

一、对象的赋值

C++允许对同一类中的不同对象之间进行对象的赋值,即将一个对象的成员值一一赋值给另一对象的

对应成员。

对象赋值语句的一般形式:

对象二对象;

例9.23对象的赋值应用

#include<iostream>

usingnamespacestd;

classabc

{public:

voidinit(inti,intj)

{a=i;b=j;}

voidshow()

{coutvvavv"u«b«endl;}

private:

inta,b;

};

voidmain()

{abcol,o2;〃声明对象oi,o2

ol.init(12,34);

o2=ol;//将对象ol的数据成员值赋值给对象o2

ol.showQ;

o2.show();

运行结果:

1234

1234

说明(P293)

(1)对象的赋值只能在同类型中进行;

(2)对象的赋值只对其中的数据成员赋值,而不对成员函数赋值;

(3)对象赋值的数据成员中不能包括动态分配的数据,否则将出现严重的后果。

二、对象的复制(拷贝)

1.对象的复制的含义

对象的复制是指:用一个已存在的对象去创建(或产生)出一个完全相同的新对象。

对象复制的一般形式:

类名对象2(对象1);//代入法

或:类名对象2=对象1;//赋值法

2.拷贝(复制)构造函数

拷贝构造函数的功能是:用一个已存在的对象的值来初始化另一个新

创建的对象。

拷贝构造函数的格式如下:

类名::拷贝构造函数名(const类名&对象名)

〃拷贝构造函数体

}

说明:

拷贝构造函数是在类声明时定义的,如果用户在类声明时未定义拷贝构造函数,将由系统自动产生一

个缺省的拷贝构造函数,以实现对象的简单复制。

例:9.24利用缺省的拷贝构造函数,以实现对象的简单复制。

#include<iostream>

usingnamespacestd;

classcoord

{public:

coord(inta,intb)〃构造函数

{x=a;

y=b;

coutvv”使用普通的构造函数"vvendl;

voidprint()〃普通成员函数

{cout«x«nn«y«endl;

private:

intx,y;

J,

intmain()

{coordpl(30,40);〃定义对象PL调用普通的构造函数

coordp2(pl);〃定义对象P2,以“代入”法调用缺省的拷贝构造函数

coordp3=pl;〃定义对象p3,以“赋值”法调用缺省的拷贝构造函数

pl.print();

p2.print();

p3.print();

return0;

交用普通的构造函数

040

040

040

ressanykeytocontinue

W9.25利用自定义的拷贝构造函数,以实现对象的复制。

#include<iostream>

usingnamespacestd;

classcoord

{public:

coord(inta9intb)〃构造函数

{x=a;

y=b;

coutvv”使用普通的构造函数"vvendl;

coord(constcoord&p)〃拷贝构造函数

{x=2*p.x;

y=2*p・y;

coutvv”使用拷贝构造函数"vvendl;

)

voidprint()〃普通成员函数

{cout«x«nH«y«endl;}

private:

intx,y;

};

intmain()

{coordpl(30,40);〃定义对象pi,调用普通的构造函数

coordp2(pl);〃定义对象p2,并以“代入”法调用拷贝构造函数,用对象pi初始化p2

pl.printQ;

p2.print();

return0;

}

运行结果:

使用普通的构造函数

使用撬贝构造函数

3040

6080

Pressanykeytocontinue

3.拷贝构造函数自动调用的三种情况

(1)当用类的一个对象去初始化该类的另一个对象时;

如上例中的:

coordp2(pl);

coordp3=pl;

(2)当函数的形参是类的对象,调用函数进行形参和实参结

合时;

(3)当函数的返回值是对象,函数执行完后返回调用者。

例9.26分析调用拷贝构造函数的三种情况

#include<iostream>

usingnamespacestd;

classcoord

{public:

coord(inta9intb);〃构造函数声明

coord(constcoord&p);〃拷贝构造函数声明

voidprint()〃普通成员函数

{cout«x«Hn«y«endl;}

private:

intx,y;

};

coord::coord(inta,intb)〃构造函数的实现

{x=a;

y=b;

coutvv”使用普通的构造函数"vvendl;

}

coord::coord(constcoord&p)〃拷贝构造函数的实现

{x=2*p.x;

y=2*p・y;

coutvv”使用拷贝构造函数"vvendl;

)

voidfunl(coordp)〃形参是类对象的普通函数

{p.print();}

coordfun2()〃返回值是类对象的函数

{coordp4(10,30);

returnp4;

intmain()

{coordpl(30,40);〃定义对象pi,第一次调用普通的构造函数

pl.printQ;

coordp2(pl);〃情况i,第一次调用拷贝构造函数,用对象pi初始化对象p2

p2.print();

coordp3=pl;〃情况i,第二次调用拷贝构造函数,用对象pi初始化对象p3

p3.print();

funl(pl);/情况2,对象pl作函数funl的实参,第3次调用拷贝构造函数

p2=fun2();〃情况3,函数的返回值是对象,第4次调用拷贝构造函数

p2.print();

return0;

更用拷贝构造函数

80

更用拷贝构造函数

)080

更用拷贝构造函数

)080

更用首通的构造函数

更用持贝构造函数

>060

5i*essanykeytocontInue

9.9静态成员

静态成员的提出上为了实现一个类的不同对象之间的数据和函数共享。

静态成员有两种,一是静态数据成员,二是静态成员函数。

一、静态数据成员

静态数据成员作为类的一种成员,他被类的所有对象共享,而不是属于某个对象的。在存储上只须存

储一处,就可以供所有对象使用。因此,可以节省内存。

例3・27|静态数据成员的引例

#include<iostream>

#include<string>

usingnamespacestd;

classstudent

{public:

student(stringnamel,stringstu_nol,floatscorel);

〃构造函数声明

voidshow();/检出姓名、学号和成绩

voidshow_count_sum_ave();〃输出学生人数、总成绩和平均成绩

private:

stringname;

stringstu_no;

floatscore;

intcount;

floatsum;

floatave;

);

student::student(stringnamel,stringstu_nol,floatscorel)

〃构造函数定义

{name=namel;

stuno=stunol;

score=scorel;

++count;

sum=sum+score;

ave=sum/count;

)

voidstudent::show()

{cout«n\nname:n«name;

cout«n\nstuno:H«stuno;

cout«H\nscore:n«score;

)

voidstudent::show_count_sum_ave()

{cout«n\ncount:H«count;

cout«H\nsum:H«sum;

cout«H\nave:H«ave;

intmain()

{studentstu1(,Timing”J990201”,90);

stul.showO;

stul.show_count_sum_ave();

studentstu2(nzhanghao990202”,85);

stu2.show();

stu2.show_count_sum_ave();

return0;

name:lining

stu_no:990201

score:90

countz-858993459

sum:-1.073?4e+008

aue:0.125

name:zhanghao

stu_no:990202

score:85

count:-858993459

sum.07374e+008

aue:0.125Pressanykeytocontinue

1.静态数据成员的定义格式:

static数据类型数据成员名;

定义为静态数据成员的变量应在定义类的对象前对其进行初始化,其初始化的格式为:

数据类型类名::静态变量名=初值;

例3.28静态数据成员的使用引例

#include<iostream>

#include<string>

usingnamespacestd;

classstudent

{public:

student(stringnamel,stringstu_nol,floatscorel);〃构造函数声明

voidshow。;/獭出姓名、学号和成绩

voidshow_count_sum_ave();/醯出学生人数、总成绩和平均成绩

private:

stringname;

stringstu_no;

floatscore;

staticintcount;〃静态数据成员,统计学生人数

staticfloatsum;〃静态数据成员,统计总成绩

staticfloatave;〃静态数据成员,统计平均成绩

);

student::student(stringnamel,stringstu_nol,floatscorel)

//w造函数定义

{name=namel;

st

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论