再上一篇:8.8 类型定义
上一篇:第九章 类和对象
主页
下一篇:9.3 对象
再下一篇:9.4 成员函数的重载
文章列表

9.2 类

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

类是对某一事物的抽象描述,具体地讲,类是C++语言中的一种导出的数据类型,它既可包含描述事物的数据,又可包含处理这些数据的函数,类在程序运行时被用作样板来建立对象的。所以要建立对象,必须先定义类。

9.2.1 定义类

定义一个类的一般格式为:

class <类名> {

《《priviate:》

<成员表1>;》

《《public:》

<成员表2>;》

《《protected:

<成员表3>;》》

};

其中关键字class指出是定义一个类;类名是程序设计者为所说明的类所起的名字,它要符合标识符的定义;成员表可以是数据说明或者是函数说明,这与结构体类型的说明是一样的;把一对花括号(“{ }”)之间的内容称为类体。类中定义的数据和函数称为这个类的成员;用关键字priviate限定的成员称为私有成员,对私有成员限定在该类的内部使用,即只允许该类中的成员函数存取私有的成员数据,对于私有的成员函数,只能被该类中的成员函数调用;用关键字public限定的成员称为公有成员,这种成员不仅允许该类中的成员函数存取公有成员数据,而且还允许该类之外的函数存取公有成员数据,公有成员函数不仅能这被该类的成员函数调用,且能被其它的函数调用;而用关键字protected所限定的成员称为保护成员,允许该类的成员函数存取保护成员数据,可调用保护成员函数,也允许该类的派生类的成员函数存取保护成员数据或调用保护成员函数,但其它的函数不能存取该类的保护成员数据,也不能调用该类的保护成员函数。有关派生类定义,在后面介绍。

关键字priviate,public,protected的作用是限定成员的访问权限,这三个关键字在类体中使用的先后顺序是无关紧要的,并且每一个关键字在类体中可使用多次。当使用一个这样的关键字(如 priviate)来限定成员的访问权限时,从紧跟该关键字后的第一个成员开始,到出现另一个限定访问权限的关键字之前的所有成员的访问权限都由该关键字所确定。同样地,在定义一个类时,类体中定义成员的顺序是无关紧要的,可先定义成员数据,也可先定义成员函数,也可将成员数据夹在成员函数之间,也可将成员函数插在成员数据之间。建议将数据成员集中在类体的前面定义,成员函数集中在类体的后面定义。这样使所定义的类清晰易读。

例 9.1 定义描述一个人的类。

分析:我们可以这样来描述一个人:姓名、性别、年龄;用一个函数RegisterPerson()登录一个人的姓名、性别和年龄;用一个函数GetName()来获取一个人的姓名;用另外二个函数GetAge()和GetSex()来分别获取一个人的年龄和性别。为此,可以将描述一个人的类定义为:class Person {

private:

char Name[12];

int Age;

char Sex[4];

public:

void RegisterPerson(const char *,int ,char *);

void GetName(char *);

int GetAge(void)

void GetSex(char *);

};

在类Person中,把成员数据Name(姓名)、Age(年龄)和Sex(性别)定义为私有成员;把四个函数定义为公有成员函数。在这类体中,当省略关键字 private时,系统默认为所定义的成员数据为私有成员,即在类体中当没有明确地指定成员的访问权限时,系统约定这些成员为私有成员。所以类Person可以等同地写为:

class Person {

char Name[12];

int Age;

char Sex[4];

public:

void RegisterPerson(const char *,int ,char *);

void GetName(char *);

int GetAge(void)

void GetSex(char *);

};

当把类Person按如下方式定义时,关键字private就不可省略了:

class Person {

public: //A

void RegisterPerson(const char *,int ,const char *);

void GetName(char *);

int GetAge(void)

void GetSex(char *);

//B

private: //C

char Name[12];

int Age;

char Sex[4];

};

在类体中,可以认为关键字private、public和proteted的都存在一个作用域,并且这三者的作用域是互斥的。这种关键字的作用域从该关键字开始到出现下一个限定关键字之前或类体结束之前结束,在其作用域内所定义的成员的访问权限,均有该关键字所限定。如上面定义的类体中,public的作用域从A行开始,到B行结束。private的作用域从C行开始,到类体结束时结束。

在以上定义的类Person中,仅给出了成员函数的函数原型,并没有给出成员函数的函数定义。在使用这些成员函数前,必须先给出这些函数的定义。定义一个类的成员函数的一般格式为:

< class_name > :: < func_name > (<参数表>)

{

...... //函数体

}

其中type是所定义函数的返回值的类型;class_name是类名;func_name是成员函数名;而运算符“::”称为作用域运算符,它指出func_name是属于类class_name的成员函数。例 9.2 定义类Person的四个成员函数。

void Person :: RegisterPerson(const char *name,int age, const char *sex)

{

strcpy(Name,name);

Age=age;

Strcpy(Sex,sex);

}

void Person ::GetName(char *name )

{

strcpy(name , Name);

}

int Person ::GetAge(void)

{

return(Age);

}

void Person ::GetSex( char *sex)

{

strcpy(sex,Sex);

}

在定义一个类时,要注意如下几点:

1、类具有封装性,并且类只是定义了一种结构(样板),所以类中的任何成员数据均不能使用关键字extern,auto或register限定其存储类型。

2、成员函数可以直接使用类中的任一成员,包括数据成员和函数成员,如上例中所示。3、在定义类时,只是定义了一种导出的数据类型,并不为类分配存储空间,所以,在定义类中的数据成员时,不能对其初始化。如:

class Test {

int x=5,y=6; //是不允许的

extern float x; //是不允许的

......

}

4、在定义一个类时,对其成员指定访问权限的原则是:若定义的成员限于该类的成员函数使用时,应指定为私有的成员;允许在类外使用成员时,应将其访问权限定义为公有的。9.2.2 类与结构体类型

从类的定义格式可以看出,类与结构体类型是类同的,类的成员可以是数据成员,也可以是函数成员,而结构体中的成员也可以是数据成员,也可以是函数成员,并且在结构体中,也可以使用关键字private、public和protected限定其成员的访问权限。实际上,在C++语言中,结构体类型只是类的一个特例。结构体类型与类的唯一的区别在于:在类中,其成员的缺省的存取权限是私有的;而在结构体类型中,其成员的缺省的存取权限是公有的。由于类与结构体类型的作用基本相同,在什么情况下定义结构体类型,而在那些情况下应定义为类呢?当前有二种观点:一种观点是在C++中,既然结构体类型是类的特例,且类具有更好的封装性,用类完全可以替代结构体,所以在程序设计中只要使用类而不必使用结构体类型;另一种观点是,仅需要描述数据结构时,使用结构体,而既要描述数据又要描述对数据进行处理的方法时,使用类。我们认为后一种观点较好。

例 9.3 定义一个三角形的结构体,结构体中包含成员函数。

#include

#include

struct tria{

private:

float x,y,z;

float area;

public:

void Setsides(float a,float b,float c)

{

if( a+b >c && b+c >a && a+c >b){

x=a; y=b; z= c;

float t = (a+b+c)/2;

area =sqrt(t*(t-a)*(t-b)*(t-c));

}

else

x=y=z=area=0;

}

void Print(void)

{

cout<<"三角形的三条边长分别是:\n";

cout<

cout<<"三角形的面积为:";

cout<

}

};

void main (void )

{

tria tr1;

tr1.Setsides(3,4,5); //A

tr1.Print(); //B

tria tr2;

tr2.Setsides(7,5,5); //C

tr2.Print( );

}

执行程序后,输出:

三角形的三条边长分别是:

3 4 5

三角形的面积为:6

三角形的三条边长分别是:

7 5 5

三角形的面积为:12.4975

在结构体tria中定义了三个私有的数据成员x,y,z,area;定义了二个公有的函数成员。A行调用了结构体变量tr1的成员函数Setsides( ),C行调用了结构体变量tr2的成员函数Setsides( ),调用成员函数的方法与使用结构体变量的数据成员的方法相同。

9.2.3 内联成员函数

当我们定义一个类时,其成员函数的函数体的定义也可以在定义类的类体中直接定义,即在类中直接定义成员函数。

例 9.4 在类体中直接定义成员函数的函数体。

class Person {

private:

char Name[12];

int Age;

char Sex[4];

public:

void RegisterPerson(const char *name,int age, const char *sex)

{

strcpy(Name,name);

Age=age;

Strcpy(Sex,sex);

}

void GetName(char *name )

{

strcpy(name,Name);

}

int GetAge(void)

{

return(Age);

}

void GetSex( char *sex)

{

strcpy(sex,Sex);

}

};

这二种定义成员函数体的方法都是可以使用的,其使用效果也是相同的。但二者是的区别在于:在定义类时,在类体中直接定义成员函数的函数体时,这种成员函数在编译时是作为内联函数来实现的,并称这种成员函数为内联成员函数;而在例 9.2中定义的成员函数并不作为内联函数来实现。通常,当函数的功能比较简单时,定义为内联成员函数;而当函数的实现比较复杂时,不使用内联成员函数。定义内联成员函数的另一种方法是,在类体中只是给出成员函数的函数原型说明,在类体外定义成员函数时,与定义一般的内联函数一样,在成员函数的定义前面加上关键字inline。

例 9.5 将类Person中的成员函数定义为内联成员函数。

class Person {

private:

char Name[12];

int Age;

char Sex[4];

public:

void RegisterPerson(const char *name,int age, const char *sex)//内联成员函数

{

strcpy(Name,name);

Age=age;

Strcpy(Sex,sex);

}

void GetName(char *);

int GetAge(void) //内联成员函数

{

return(Age);

}

void GetSex( char *sex)

{

strcpy(sex,Sex);

}

};

inline void Person :: GetName(char *name ) //内联成员函数

{

strcpy(name,Name);

}

在本例中,用二种方法对类Person的三个成员函数都定义为内联成员函数。这二种方法定义的内联成员函数,在其作用和使用上都是完全一样的。