再上一篇:第九章 类和对象
上一篇:9.2 类
主页
下一篇:9.4 成员函数的重载
再下一篇:9.5 this指针
文章列表

9.3 对象

《VC++程序设计基础》,讲述C++语言的语法和标准库,以及Visual C++ 函数库和MFC类库的使用,并附相关代码示例。

前已述及,只定义结构体的类型,而不定义结构体的变量,那么这种结构体的类型是没有任何实用意义的。同样地,类是用户定义的一种类型,程序设计者可以使用这种类型名来说明变量。具有类类型的变量称为对象,也把对象称为类的实例。对象的使用方法与结构体变量的使用方法相同。

9.3.1 对象的说明

对象与结构体变量一样,必须先定义后使用。说明对象的一般格式为:

《存储类型》clase_name object1《 ,object2,......》;

其中存储类型是指定对象的存储类型,clase_name是一个已经定义过的一个类名,object1、object2是为对象起的名字,对象名要符合标识符的定义。例如:

Person p1,p2;

说明了二个对象p1和p2,它们均是类Person的对象。

注意,系统并不为类分配存储空间,如同不为结构体类型分配空间一样,当说明对象时,系统才为对象分配相应的存储空间。为对象分配存储空间的大小取决于在定义类时所定义的成员的类型和成员的多少。在程序执行时,通过为对象分配存储空间来创建对象。在创建对象时,类被用作样板,因此对象称为类的实例。表9.1给出类Person的二个实例 p1和p2的示意说明。

表9.1 类Person的二个实例 p1和p

对象p1 对象p2

p1. Name p2. Name

p1. Age p2. Age

p1. Sex p2. Sex

p1. RegisterPerson( ) p2. RegisterPerson( )

p1. GetName( ) p2. GetName( )

p1. GetAge( ) p2. GetAge( )

p1. GetSex( ) p2. GetSex( )

不同对象占据内存中的不同区域,它们所保存的数据各不相同,但对成员数据进行操作的成员函数的程序代码均是一样的。如p1. Name 和p2. Name 的值可以是不同的,但p1.GetName( )和p2. GetName( )的代码是相同的。为了减少成员函数所占用的空间,在建立对象时,只为对象分配用于保存数据成员的内存空间,而成员函数的代码为该类的每一个对象所共享。通常,类中定义的成员函数的代码被放在计算机内存的一个公用区中,并供该类的所有对象共享。这是C++实现对象的一种方法。逻辑上,我们仍将每一个对象理解为由独立的成员数据和各自的成员函数代码组成。

说明对象的方法与说明结构体变量的方法一样,也可有三种:第一种是先定义类的类型,再说明对象;第二种方法是在定义类的同时,说明对象;第三种方法是直接说明对象,而不定义类的类名。

例 9.6 用三种方法定义对象。

class A{

public:

int r,t;

};

A x,y; //先定义类,再定义对象

class B{

int I,j;

public:

void Setdata(int a, int b)

{ I =a; j=b; }

void Print( void)

{ cout<< I<<’\t’<

} b1,b2; //定义类的同时,定义对象

class {

public :

int c,d;

} t1, t2={100,200}; //C 不定义类的类名,直接定义对象

在定义结构体变量时,允许对它的数据成员进行初始化。在定义对象时,是否允许对它的数据成员进行初始化呢?当类中的数据成员的访问权限指定为公有的时,定义对象时,允许对它的数据成员进行初始化。C行为对象t2的数据成员c和d分别初始化为100和200。当类中的数据成员的访问权限指定为私有的或保护的时,定义对象时,不允许对它的数据成员进行初始化。如:

B b3={500,600};

这是不允许的。实际上,在结构体类型中,把它的数据成员定义为私有时,在说明结构体变量时,同样也不允许对这种数据成员进行初始化。对对象中的数据成员进行初始化,通常采用定义构造函数或采用拷贝初始化构造函数的方法来实现。这二种函数在后面介绍。9.3.2 对象的使用

由于结构体变量是对象一个特例,所以对象的使用方法与结构体变量的使用方法也基本类同,但对于公有成员、私有成员及保护成员,在使用上是有差异的。我们通过一个例子来说明之。

例 9.7 描述一个矩形对象,设置矩形的坐标并输出其相应的坐标值。

分析:一个矩形可用左上角和右下角的二个坐标点来描述,左上角坐标用(left,top)来表示,右下角的坐标用(right,bottom)来描述。假定这四个数的取值均是大于0的正整数。#include

#include

class CRect{

private:

int left,top;

public:

int right,bottom;

void setcoord(int,int,int,int); //设置坐标值函数

void getcoord(int *L,int *R,int *T,int *B) //取坐标值的函数

{

*L=left;*R=right;

*T=top; *B=bottom;

}

void Print(void)

{

cout<<"面积="<

}

};

void CRect::setcoord(int L,int R,int T,int B)

{

left= L; right=R;

top=T ; bottom=B;

}

void main(void)

{

CRect r ,rr ;

int a,b,c,d;

r.setcoord(100,300,50,200);

cout << "right ="<< r.right<<'\n';

cout << "bootom ="<< r.bottom<<'\n';

r.getcoord(&a,&b,&c,&d);

cout << "left="<

cout << "top="<

r.Print( );

rr = r ; //A

rr.Print( );

}

执行程序后的输出为:

right =300

bootom =200

left=100

top=50

面积=30000

面积=30000

结合上例,有关对象的使用说明以下几点:

1、要用成员选择运算符“.”来访问对象的成员。如上例中的r.right和r.getcoord()。当访问一个成员函数时,也称为向对象发送一个消息。用成员选择运算符“.”只能访问对象的公有成员,而不能访问对象的私有成员或保护成员。如:

a=r.left;

b= r.right;

都是不允许的(产生编译错误),因成员left和right都是私有的成员。若要访问对象的私有的数据成员,只能通过对象的公有成员函数来获取。如上例中用成员函数r.getcoord(&a,&b,&c,&d)来获取对象r的坐标值。

2、同类型的对象之间可以整体赋值。如:

rr = r;

将对象r的所有成员依次赋给对象rr的成员。这种赋值与对象的成员的访问权限无关。

3、对象用作函数的参数时,属于赋值调用;函数可以返回一个对象。这与结构体变量作为函数的参数是完全相同的。

4、与结构类型的变量一样,可以定义类类型的指针,类类型的引用,对象数组,指向类类型的指针数组和指向一维或多维数组的指针变量。如:

CRrect a[10], *p, b, &pb=b, *pp[5],(*pa)[4];

定义a为对象数组,p为指向对象的指针变量,pb为对象b的引用,pp为指向对象的指针数组,pa为指向一维数组的指针变量。

5、一个类的对象,可作为另一个类的成员。如:

class A{

......;//类A的类体定义

};

class B{

A a1,a2;

......;

};

这里,类B中定义了私有成员a1,a2,这二个成员都是类A的对象。当类中的成员是对象时,也不能指定这种对象的存储类型为 auto,register,extern。正如前面所说,类中的任何成员均不能指定为这三种存储类型。

9.3.3 类作用域、类类型的作用域和对象的作用域

在定义类时,用一对花括号将类体括起来的区域称为类的作用域。在类作用域中说明的标识符仅在该类的类作用域内有效,即这种标识符的可见性在类作用域之内。如:

class D{

public:

int I,l;

void Print( void ) {cout<<”I=”<

};

I = 35; //因I 不可见,所以不能对其赋值

类的成员函数,不论是内联的还是非内联的,其函数名的作用域都是属于类的作用域,故都不能直接通过函数名来调用函数。如:

Print( ) ; //因成员函数不可见,所以不能直接调用

类的类型名的作用域与标识符的作用域相同,在函数定义之外定义的类,其类名的作用域为文件作用域;而在函数体内定义的类,其类名的作用域为块作用域。类的说明也分为引用性说明和定义性说明。在说明一个类时,没有给出类体而仅给出类名时,属于类的引用性说明。引用性说明的类不能用来建立对象,只能用来说明函数的形参、指针和引用。如:

class CC ;

CC C1; //因类CC是引用性说明,故不能用来建立对象

class X{

CC c3,c4; //A

CC *pc; //B

......

};

A行在编译时给出语法错误,因类CC是引用性说明,也不能定义类的成员对象。B行是正确的,因成员pc 是指向类的指针。

对象的作用域与前面介绍的变量作用域完全相同,不作重复介绍了。

9.3.4 类的嵌套

在定义一个类时,在其类体中又包含了一个类的定义时称为类的嵌套。例如:

class Outer{

public:

class Inner{ //A

public:

int x,y;

};

Inner c1,c2; //B

float a,b;

}; //C

相对于类Outer而言,类Inner是嵌套类。可以把嵌套类看作是一种成员类。系统并不为嵌套类分配内存空间,在B行是说明这嵌套类的对象,在定义类Outer时,系统也不为嵌套类对象分配内存空间。嵌套类的类名的作用域从其定义开始,到其外层类的定义结束时结束。如例中的类名Inner的作用域从A行开始,到C行结束。在定义类Outer的对象时,才为嵌套类的对象分配存储空间。