对象成员的引用

2015/05/24 C和C++基础

在程序中经常需要访问对象中的成员。访问对象中的成员可以有3种方法。

通过对象名和成员运算符访问对象中的成员

例如在程序中可以写出以下语句:

stud1.num=1001;   //假设num已定义为公用的整型数据成员

表示将整数1001赋给对象stud1中的数据成员num。其中“.”是成员运算符,用来对成员进行限定,指明所访问的是哪一个对象中的成员。

访问对象中成员的一般形式为:

对象名.成员名

不仅可以在类外引用对象的公用数据成员,而且还可以调用对象的公用成员函数,但同样必须指出对象名,如:

stud1.display( );    //正确,调用对象stud1的公用成员函数
display( );          //错误,没有指明是哪一个对象的display函数

应该注意所访问的成员是公用的(public)还是私有的(private)。只能访问public成员,而不能访问private成员。在类外只能调用公用的成员函数。在一个类中应当至少有一个公用的成员函数,作为对外的接口,否则就无法对对象进行任何操作。

通过指向对象的指针访问对象中的成员

指向结构体变量的指针,可以通过指针引用结构体中的成员。用指针访问对象中的成员的方法与此类似。 比如:

class Time
{public:         //数据成员是公用的
	int hour;
	int minute;
};

Time t,*p;      //定义对象t和指针变量p
p=&t;           //使p指向对象t
cout<<p->hour;  //输出p指向的对象中的成员hour

在p指向t的前提下,p->hour,(*p).hour和t.hour三种方法进行访问。

通过对象的引用变量来访问对象中的成员

如果为一个对象定义了一个引用变量,它们是共占同一段存储单元的,实际上它们是同一个对象,只是用不同的名字表示而已。因此完全可以通过引用变量来访问对象中的成员。如果已声明了Time类,并有以下定义语句:

Time t1;        //定义对象t1
Time &t2=t1;    //定义Time类引用变量t2,并使之初始化为t1
cout<<t2.hour;  //输出对象t1中的成员hour

由于t2与t1共占同一段存储单元(即t2是t1的别名),因此t2.hour就是t1.hour。

公用接口与私有实现的分离

C++通过类来实现封装性,把数据和与这些数据有关的操作封装在一个类中,或者说,类的作用是把数据和算法封装在用户声明的抽象数据类型中。在声明了一个类以后,用户主要是通过调用公用的成员函数来实现类提供的功能(例如对数据成员设置值,显示数据成员的值,对数据进行加工等)。因此,公用成员函数是用户使用类的公用接口(public interface),或者说是类的对外接口。

当然并不一定要把所有成员函数都指定为public(公用)的,但这时这些成员函数就不是公用接口了。在类外虽然不能直接访问私有数据成员,但可以通过调用公用成员函数来引用甚至修改私有数据成员。用户可以调用公用成员函数来实现某些功能,而这些功能是在声明类时已指定的,用户可以使用它们而不应改变它们。实际上用户往往并不关心这些功能是如何实现的细节,而只需知道调用哪个函数会得到什么结果,能实现什么功能即可。通过成员函数对数据成员进行操作称为类的实现,为了防止用户任意修改公用成员函数,改变对数据进行的操作,往往不让用户看到公用成员函数的源代码,显然更不能修改它,用户只能接触到公用成员函数的目标代码。

可以看到:类中被操作的数据是私有的,实现的细节对用户是隐蔽的,这种实现称为私有实现(private implementation)。这种“类的公用接口与私有实现的分离”形成了信息隐蔽。

软件工程的一个最基本的原则就是将接口与实现分离,信息隐蔽是软件工程中一个非常重要的概念。它的好处在于:

(1)如果想修改或扩充类的功能,只需修改本类中有关的数据成员和与它有关的成员函数,程序中类外的部分可以不必修改。

(2)如果在编译时发现类中的数据读写有错,不必检查整个程序,只需检查本类中访问这些数据的少数成员函数。

类声明和成员函数定义的分离

在面向对象的程序开发中,一般做法是将类的声明(其中包含成员函数的声明)放在指定的头文件中,用户如果想用该类,只要把有关的头文件包含进来即可,不必在程序中重复书写类的声明,以减少工作量,节省篇幅,提高编程的效率。

由于在头文件中包含了类的声明,因此在程序中就可以用该类来定义对象。由于在类体中包含了对成员函数的声明,在程序中就可以调用这些对象的公用成员函数。为了实现上一节所叙述的信息隐蔽,对类成员函数的定义一般不放在头文件中,而另外放在一个文件中。

可以分别写两个文件:

//student.h (这是头文件,在此文件中进行类的声明)
class Student          //类声明
{
public:
	void display( );   //公用成员函数原型声明
private:
	int num;
	char name[20];
	char sex;
};
//student.cpp            //在此文件中进行函数的定义
#include <iostream>
#include"student.h"      //不要漏写此行,否则编译通不过
void Studen::display()  //在类外定义display类函数
{
	cout<<"num:"<<num<<endl;
	cout<<"name:"<<name<<endl;
	cout<<"sex:"<<sex<<endl;
}

为了组成一个完整的源程序,还应当有包括主函数的源文件:

//main.cpp            主函数模块
#include <iostream>
#include"student.h"   //将类声明头文件包含进来
int main( )
{
	Student stud;     //定义对象
	stud.display( );  //执行stud对象的display函数
	return 0;
}

这是一个包括3个文件的程序,组成两个文件模块:一个是主模块main.cpp,一个是student.cpp。在主模块中又包含头文件student.h。在预编译时会将头文件student.h中的内容取代#include”student.h”行。

请注意:由于将头文件student.h放在用户当前目录中,因此在文件名两侧用双撇号包起来(“student.h”)而不用尖括号(),否则编译时会找不到此文件。

类库有两种:一种是C++编译系统提供的标准类库;一种是用户根据自己的需要做成的用户类库,提供给自己和自己授权的人使用,这称为自定义类库。在程序开发工作中,类库是很有用的,它可以减少用户自己对类和成员函数进行定义的工作量。类库包括两个组成部分:

(1)类声明头文件;

(2)已经过编译的成员函数的定义,它是目标文件。

用户只需把类库装入到自己的计算机系统中(一般装到C++编译系统所在的子目录下),并在程序中用#include命令行将有关的类声明的头文件包含到程序中,就可以使用这些类和其中的成员函数,顺利地运行程序。

这和在程序中使用C++系统提供的标准函数的方法是一样的,例如用户在调用sin函数时只需将包含声明此函数的头文件包含到程序中,即可调用该库函数,而不必了解sin函数是怎么实现的(函数值是怎样计算出来的)。当然,前提是系统已装了标准函数库。在用户源文件经过编译后,与系统库(是目标文件)相连接。

在用户程序中包含类声明头文件,类声明头文件就成为用户使用类的公用接口,在头文件的类体中还提供了成员函数的函数原型声明,用户只有通过头文件才能使用有关的类。用户看得见和接触到的是这个头文件,任何要使用这个类的用户只需包含这个头文件即可。包含成员函数定义的文件就是类的实现。请特别注意:类声明和函数定义一般是分别放在两个文本中的。

由于要求接口与实现分离,为软件开发商向用户提供类库创造了很好的条件。开发商把用户所需的各种类的声明按类放在不同的头文件中,同时对包含成员函数定义的源文件进行编译,得到成员函数定义的目标代码。软件商向用户提供这些头文件和类的实现的目标代码(不提供函数定义的源代码)。用户在使用类库中的类时,只需将有关头文件包含到自己的程序中,并且在编译后连接成员函数定义的目标代码即可。由于类库的出现,用户可以像使用零件一样方便地使用在实践中积累的通用的或专用的类,这就大大减少了程序设计的工作量,有效地提高了工作效率。

Search

    Post Directory