Chap3 类和对象800Word文档格式.docx

上传人:b****6 文档编号:21247780 上传时间:2023-01-28 格式:DOCX 页数:16 大小:40.63KB
下载 相关 举报
Chap3 类和对象800Word文档格式.docx_第1页
第1页 / 共16页
Chap3 类和对象800Word文档格式.docx_第2页
第2页 / 共16页
Chap3 类和对象800Word文档格式.docx_第3页
第3页 / 共16页
Chap3 类和对象800Word文档格式.docx_第4页
第4页 / 共16页
Chap3 类和对象800Word文档格式.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

Chap3 类和对象800Word文档格式.docx

《Chap3 类和对象800Word文档格式.docx》由会员分享,可在线阅读,更多相关《Chap3 类和对象800Word文档格式.docx(16页珍藏版)》请在冰豆网上搜索。

Chap3 类和对象800Word文档格式.docx

intSet_Content(char*);

//设置字符串

intGet_Length();

//取字符串长度

char*Get_Content();

//取字符串内容

};

4.巩固练习——1(类声明)

3.2成员函数的定义(MemberFunction)

1.两种定义方式:

1在类体中声明,而在类外定义。

声明时,可以只指出函数所带参数的类型;

在类外定义时,必须在函数名前缀上类名,以标明此函数所属的类。

如,上例中的String类中的三个成员函数可定义如下:

//string_1.cpp

//功能:

设置私有变量contents的值,同时计算其长度

intString:

:

Set_Content(char*conts)

{

inti=0;

contents=conts;

//将字符串赋给私有变量contents

while(*conts++!

=‘\0’)

i++;

//求字符串长度

length=i;

//将长度赋给私有变量length

return1;

}

获取字符串的长度

Get_Length()

returnlength;

//返回私有变量length

获取字符串的值

char*String:

Get_Content()

returncontents;

//返回私有变量contents

注意:

Ø

在所定义的成员函数名之前应缀上“类名:

”,如“String:

函数的返回类型一定要与函数声明时的类型相匹配

2在类体内定义。

对于一些简单的成员函数,可以在类体中定义。

在类体内定义的成员函数被当作内联函数处理

2.内联函数的两种定义方式

1隐式定义——类体内定义

//point.h

intx,y;

voidSetPoint(intvx,intvy)

intGetX(){returnx;

}

intGetY(){returny;

//string_1.h

intGet_Length(){returnlength;

char*Get_Content(){returncontent;

2显式定义——类体外定义,函数最前面冠以关键字“inline”

//point.cpp

inlinevoidPoint:

SetPoint(intvx,intvy)

x=vx;

y=vy;

【小结】

①所有成员函数都必须在类体内用函数原型加以声明,而其定义可在体外定义,也可在体内定义。

在体外定义时,成员函数名前应缀上“类名:

②成员函数与普通函数一样,可设置缺省参数。

3.3类与对象

1.类与对象的关系——整型int和整型变量i之间的关系

●类在概念上是一种抽象机制,它抽象了具有相同特征的一类对象的存储特性和操作特性;

在系统实现中,类是一种共享机制,它提供了本类对象共享的操作实现。

●对象和实例表达的是一个意思:

对象的创建过程就是类实例化的过程

●创建对象的两种方法

①在定义类的同时创建对象——全局对象(弊端:

//date.h

classDate{

intmonth,day,year;

voidSet(int,int,int);

voidPrint();

intGetYear();

intGetMonth();

intGetDay();

}tt;

//同时创建对象tt

②在使用时定义对象——定义格式与一般变量的定义相同

如,Datett;

//定义了tt是Date类的一个对象

2.类的使用

创建一个此类的对象,然后通过此对象访问类的公有成员函数,以便操作此对象的数据成员。

classPoint{

voidSetPoint(intvx,intvy){x=vx;

……

//test.cpp

#include“iostream.h”

voidmain()

{

Pointpt;

//创建Point类的对象pt

pt.SetPoint(10,10);

//给Point类对象pt的私有成员赋值

cout<

<

”x=”<

pt.GetX();

//输出pt的坐标

”,y=”<

pt.GetY();

}

使用“.”操作符访问类的成员。

若定义的是指向此类对象的指针,则使用“->

”操作符。

如:

Pointpt,*pt1=&

pt;

pt1->

SetPoint(10,10);

pt1->

GetX();

GetY();

3.名字解析

在调用成员函数时,通常使用缩写的形式,如

pt.SetPoint(10,10)pt.Point:

SetPoint(10,10);

因此,可以在不同的类中定义名字相同的成员而不会产生二义性。

(函数重载?

如,//real_int_set.h

classRealSet{//定义一个实数集合类

intcard;

floatelems[16];

voidPrint(){//…}

classIntSet{//定义一个整数集合类

intelems[16];

//test.cpp

voidmain()

IntSetis;

RealSetrs;

//...

is.Print();

//调用的是InSet类中的Print()

rs.Print();

//调用的是RealSet类中的Print()

4.巩固练习——2(成员的调用)

3.4构造函数与析构函数

目的:

构造函数初始化对象

析构函数删除对象

3.4.1基本用法

①函数名与类名相同,且没有返回类型。

classString{

char*contents;

intlength;

String();

//声明构造函数,其名必须与类名相同,无类型说明

~String();

//声明析构函数,在函数名前冠以“~”符号

voidSet_Content(char*);

intGet_Length(){returnlength;

char*Get_Content(){returncontent;

//构造函数的定义

String:

String()

contents=0;

//对其私有变量赋初值

length=0;

//析构函数的定义

~String()

{

//设置私有变量contents的值,同时计算其长度

②在构造函数中一般只对数据成员做初始化工作,而不做赋初值以外的事情。

③构造函数不可显式地调用,当创建一个对象时,系统自动地调用。

在对象超出作用域范围之前,系统自动调用析构函数,释放对象的成员所占的空间。

//对私有变量赋初值

cout<

”StringInitialized\n”;

//在屏幕上输出对象已初始化的信息

~String()

”~Stringobject”<

contents<

endl;

Stringstr1,str2;

//定义String的两个对象str1和str2

str1.Set_Content(“Hello”);

//给两个对象的字串赋值

str2.Set_Content(“Welcome”);

//在屏幕上输出两个对象的字串值

cout<

”\nstr1=”<

str1.Get_Content();

”\nstr2=”<

str2.Get_Content();

显示结果:

StringInitialized

StringInitialized

str1=Hello

str2=Welcome

~StringobjectWelcome

~StringobjectHello

创建一个对象时,系统先为对象分配内存,然后调用构造函数初始化此对象的各数据成员(即:

设置对象的初始状态)

释放一个对象时,系统先调析构函数,然后回收对象所占的内存。

如deletestr1;

//①str1.~String()②回收内存

析构对象的顺序与构造的顺序相反。

若类中没有显式定义构造函数,在创建对象时,系统只分配内存,而不执行初始化工作,对象的各个数据将是随机值。

此时若对对象的数据进行操作,将导致结果错误!

(缺省的构造函数)

若类中没有显式定义析构函数,系统会生成一个缺省的析构函数;

但缺省的析构函数只回收对象所占有的空间,并不回收通过构造函数动态分配的内存(内存泄漏!

)(后讲!

④一个类有且只有一个析构函数。

3.5动态存储(new与delete)

newmalloc(sizeof());

deletefree();

1.优越性:

①new自动计算要分配的空间(根据数据类型)

②自动返回正确的指针类型,不必对返回指针进行类型转换

③可以用new将分配的对象初始化

2.new和delete的语法

基本形式:

名字指针=newDataType(初始化值);

delete名字指针;

//被释放的存储空间的首址

①动态创建和释放一个对象

int*pi=newint(3);

/*int*pi=(int*)malloc(sizeof(int));

*pi=3;

*/

deletepi;

//free(pi);

②创建和释放一组对象(数组)

int*pi=newint[10];

delete[]pi;

//释放整个数组所占用的空间

③创建和释放结构体对象

3.实例(1~4)

4.使用注意:

delete前,必须判断指针是否为空,即if(p==NULL)orif(!

p)

以免同一空间进行多次撤消工作,导致非法操作!

new和delete一般配对使用,即:

用new分配的存储,最好用delete释放

动态分配的存储,必须显式删除(delete/free),系统不会自动回收,否则造成内存泄漏!

3.4.2构造函数的类型

1.带参数的构造函数

①在定义对象时,根据对象的初始状态不同,传递不同的状态参数给构造函数,从而实现不同对象的初始化状态不同。

如,

//test.cpp

Point(intvx,intvy);

//声明带参数的构造函数

voidoffset(intax,intay);

};

Point:

Point(intvx,intvy)

{

//用传递进来的参数对私有变量x,y赋初值

voidPoint:

offset(intax,intay)

x+=ax;

//对私有变量增值x=x+ax;

y+=ay;

voidmain()

//定义对象pt1和pt2,并给构造函数传递实参

Pointpt1(5,5),pt2(3,3);

pt1.offset(10,15);

pt2.offset(2,3);

//......

2.缺省参数的构造函数

Point(intvx=0,intvy=0){x=vx;

//.......

Pointp1;

//不传递参数,全部用缺省值,即x=y=0

Point(10);

//只传递一个参数,vy用缺省值,即x=10,y=0

Point(10,20);

//传递两个参数,全部用实参,即x=10,y=20

构造函数、一般的成员函数、一般的全局函数,都可以使用缺省参数。

3.拷贝构造函数

功能:

用同类的一个已存在的对象去初始化新创建的对象

两种形式:

①系统自动产生——缺省的拷贝构造函数,如

Pointp1(10,20);

//调用Point(int,int)

Pointp2=p1;

/*用已知对象初始化新对象

Pointp2(p1);

调用缺省的拷贝构造函数*/

实现机制:

将p1(已知对象)的每个数据成员的值,按照它们在类中说明的顺序,依次拷贝给新对象p2相应的数据成员,每次只拷贝一个数据,即“位模式拷贝”。

“位模式拷贝”产生的隐患:

#include<

string.h>

#include<

iostream.h>

intlength;

char*contents;

public:

String(char*s);

//声明构造函数

~String();

//

//…

String:

String(char*s)//定义构造函数

{

if(s)

{

length=strlen(s);

contents=newchar[length+1];

//为字符串分配存储

strcpy(contents,s);

//字符串之间赋值

else

length=0;

contents=0;

~String()//定义析构函数

if(content)

deletecontents;

//释放字符串contents所占空间

contents=0;

//将指针置空

voidmain()

Stringa(“Hust”);

Stringb=a;

}//同一存储空间contents被delete两次

当类中声明有指针数据成员时,为避免程序隐患,最好自行编写拷贝构造函数。

②用户定义

格式:

A:

A(constA&

)//A为类名

注:

只有一个参量,且参量是同类对象的引用变量(如A&

);

多采用只读引用变量(如constA&

),以免被引用对象被修改。

intx,y;

Point(intvx,intvy){x=vx;

Point(constPoint&

rp)//定义一个拷贝构造函数

{x=rp.x;

y=rp.y;

String(constString&

rs);

//定义拷贝构造函数

String(constString&

rs)//定义拷贝构造函数

length=rs.length;

strcpy(contents,rs.content);

Stringa(“Hust”);

Ab=a;

4.多构造函数(构造函数的重载)

在一个类中同时声明几个构造函数,以适应不同对象初始化目的。

classA{

A();

//不带参数的构造函数

A(int);

//只带一个int参数的~

A(int,char);

//带两个参数的~,一个整数,一个字符

A(float,char);

//带两个参数的~,一个浮点数,一个字符

A(constA&

);

//拷贝构造函数

main()

Aa;

Ab

(1);

Ac(1,’c’);

Ad(3.5,’d’);

Ae=a;

注1:

多个构造函数之间,在参数的个数或类型上必须有所差别,否则系统调用时就会出现二义性

注2:

若在定义多个构造函数时,使用了缺省参数,要防止二义性问题

如,classx

x();

x(inti=0);

main()

xone(10);

//

xtwo;

//?

?

3.4.3动态存储类的对象(new与delete)

1.创建和释放一个对象

Point*pt;

//对象指针

pt=newPoint(10,10);

//...

deletept;

实例5>

2.创建和释放一组对象(数组)

Point*pt=newPoint[2];

//对象数组

delete[]pt;

对数组动态分配存储时,不能同时对数组中的元素进行初始化。

若要实现对象数组中元素的初始化,可按下面两种方法:

①在类中定义不带参数的构造函数或全部带缺省参数的构造函数(实例6)

②在类中定义一个成员函数专门用来完成初始化功能;

对象数组被创建后,通过调用此函数来对数组中的对象元素进行初始化

对象数组的初始化方法同基本类型的数组

如,inta[2];

a[0]=1;

Aa[2];

a[0]=A

(1);

inta[3]={1,2,3};

Aa[3]={A

(1),A(1,’a’),a[0]};

若创建多维数组,必须提供所有维的大小。

int*qi=newint[2][3][5];

int*qi=newint[][3][5];

//×

参看教材【例3.18】>

3.使用注意:

对简单的数据类型,以及没有显示定义构造函数和析构函数的类,两种管理内存的方式可以混合使用,即new分配的内存可用free释放,malloc分配的内存可用delete释放。

但若一个类显示定义了构造和析构函数,则最好用new和delete分配和释放内存。

动态分配的存储,必须显式删除(delete/free),否则造成内存泄漏!

3.4.4小结

构造函数和析构函数是一种特殊的成员函数,其个性:

①都没有返回类型,即在定义时不需指出类型

②构造函数可以有缺省参数,但要注意避免二义性

③构造函数可重载,但析构函数不可重载(唯一性)

④构造函数不可显式调用,但析构函数可以

⑤当创建(定义)对象时,系统自动调用构造函数;

当删除对象时,系统自动地调用析构函数(C++新特点:

提供了自动回收和显式回收两种内存管理方式)

⑥都不能被继承

⑦析构函数可以是虚的(virtual),但构造函数不行

3.4.5巩固练习

练习1——改错(1-6)

练习2——成员的访问和对象的定义:

2

练习3——写出输出结果:

1

看懂教材第3章所有例子!

重点:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1