3.2 对象
在面向对象程序设计方法中,类是一种封装数据与函数的形式,但在程序中,类是一种复杂的构造数据类型,可以用来定义变量,这个变量称为具有类属性的对象,是类的一个实例,因此在面向对象程序中,类是程序设计的核心,而对象是程序的实体。
3.2.1 对象的创建
类是用户定义的一种数据类型,因此程序员可以使用这个类型在程序中定义变量,这种具有类类型的变量就称为对象,具体示例如下:
Point p1,p2;
定义对象的格式与定义普通变量是一样的,只要已经定义了类,就可以定义对象。类定义仅提供该类的类型,不占用内存空间,只有在定义了类的对象后,编译系统才会给对象在内存中分配相应的内存空间。对象与类的区别如表3.2所示。
每个对象占据内存中的不同区域,它们所保存的数据成员是不同的,但函数成员都是相同的。在C++中,为节省内存,在创建对象时,只分配用于保存数据成员的内存,而函数成员被放在计算机内存的一个共用区中为每个对象所共享,如图3.2所示。但为了便于理解,读者仍然可以将对象理解为由数据成员和函数成员组成的封装体。
表3.2 类与对象的区别
图3.2 类的对象在内存中的分布
3.2.2 对象中成员的访问
定义了类及对象后,就可以通过对象来访问其中的成员。访问的方式包括圆点访问形式和指针访问形式。对象只能用前一种方式访问成员,而指向对象的指针用两种方式都可以访问。
1. 圆点访问形式
圆点访问形式就是使用成员运算符“.”来访问对象中的成员,具体示例如下:
对象名.成员 (*指向对象的指针).成员
成员包括数据成员和成员函数,在类的定义内部,所有成员之间可以相互直接访问,但在类的外部,只能以上述格式访问对象的公有成员。主函数也在类的外部,因此在主函数中定义的类对象,在操作时只能访问其公有成员。
2. 指针访问形式
指针访问形式是使用成员访问运算符“->”来访问对象的成员,该运算符前面必须是一个对象的地址,具体示例如下:
使用这种形式访问成员,需要先定义指向该类型的指针变量,在该指针指向某个对象后,再使用这种形式访问。
接下来演示这两种方式访问对象中的成员,如例3-1所示。
例3-1
运行结果如图3.3所示。
图3.3 例3-1运行结果
在例3-1中,第29行通过圆点访问形式访问对象p1中的成员,第31行通过指针访问形式访问p2中的成员。第35行通过运算符“∗”将指针形式转化为圆点形式。读者在使用时,根据实际情况灵活运用这两种访问形式。
3.2.3 this指针
在创建对象时,系统只分配用于保存数据成员的内存,而成员函数为每个对象所共享,this指针将对象和该对象调用的成员函数联系起来,从外部来看,好像每个对象都有自己的成员函数,因此说this指针是C++实现封装的一种处理机制。
this指针是一种隐含指针,它隐含于每个类的成员函数之中,用于指向该成员函数所属的对象。当成员函数被调用时,系统自动向它传递一个隐含参数,该参数就是指向调用该函数对象的指针,从而使成员函数知道对哪个对象进行操作。
例如,例3-1中定义的Point类的成员函数init()定义如下:
若执行下面语句:
Point p1,p2; p1.init(3,4);
则p1.x与p1.y会被赋值,但成员函数init()是对象p1和p2共享的,系统通过this指针对p1与p2加以区分。当执行语句“p1.init(3,4);”时,成员函数init()的this指针就指向p1,这样成员函数中的x和y就是指p1的数据成员x和y,而不是其他对象的。事实上,C++编译所认识的成员函数init()定义形式如下:
对象调用成员函数init()形式如下:
Point p1,p2; p1.init(&p1,3,4);
从上可以得出成员函数与非成员函数的区别:成员函数的参数列表里有个隐含的this指针。通常编程者不必人为地在形参中添加this指针,也不必将对象的地址传给this指针。this指针不能显示的定义,编程者只能使用它,通常如果希望成员函数返回本类对象或者本对象地址,则可以使用this指针,具体示例如下:
return *this; return this;
另外,当成员函数的形参名与该类的成员变量名相同时,必须使用this指针来显示区分,例如,成员函数init()定义形式如下:
类Point中的私有数据成员x、y与成员函数init()的形参同名,此处正是使用了this指针,从而使函数中的赋值语句合法有效。如果没有使用this指针,则init()函数中的赋值语句就变成为“x=x;y=y;”,编译时编译器就会报错。