把操作符应用在这些类对象上的方式与应用在内置数据类型上的对象一样,下面给出
两个IntArray 对象:
IntArray myArray0, myArray1;
赋值操作符可以这样应用
// 调用拷贝赋值成员函数
// myArraya.operator=( myArray1 )
myArray0 = myArray1;
等于操作符的调用如下所示
// 调用等于成员函数
// myArray0.operator==( myArray1 )
if ( myArray0 == myArray1 )
cout << "!!our assignment operator works!\n";
关键字private 和public 控制对类成员的访问,出现在类体中,公有public 部分的成员
在一般程序的任何地方都可以访问它们,出现在私有private 部分的成员只能在该类的成
员函数或友元friend 中被访问,我们要到15.2 节才会解释友元
一般来说,公有成员提供了该类的公有接口public interface ——即实现了这个类的行
为的操作集合。它包括该类的所有成员函数或者只包括其中一个子集,私有成员提供私有
实现代码private implementation ——即存储信息的数据。
这种类的公共接口与私有实现代码的分离被称为信息隐藏information hiding。
信息隐藏是软件工程中一个非常重要的概念,在后面的章节中将为详细的介绍简要说来
它为程序提供了两个主要好处
1 如果类的私有实现代码需要修改或扩展,那么只有相对很小一部分要求访问这些,
实现代码的成员函数需要修改而许多使用该类的用户程序无需修改,但是要求重新编译
2 如果类的私有实现代码有错误,那么通常需要检查的代码数量只局限在相对较少的需
要访问这些实现代码的成员函数上,而无需检查整个程序
哪些数据成员是IntArray 必需的呢?当声明一个IntArray 对象时,用户会指定数组大小
我们需要存储它,因此我们将定义一个数据成员来做到这一点,另外我们需要实际分配
并存储底层的数组,这将通过new 表达式来实现,我们将定义一个指针数据成员来存储new
表达式返回的地址值
class IntArray {
public:
// ...
int size() const { return _size; }
private:
// 内部数据
int _size;
int *ia;
};
由于我们把_size 放在类的私有区内,因此我们有必要声明一个公有成员函数以便允
许用户访问它的值,由于C++不允许成员函数与数据成员共享同一个名字,所以在这样的情
况下一般的习惯是在数据成员名字前面加一个下划线_ ,因此我们有了公有访问函数
size()和私有数据成员_size,在本书以前的版本中,我们在访问函数前加上get 或set ,实践证
明这样做有些累赘。
尽管这种公有访问函数的用法允许用户读取相应的值,但是这种实现似乎还有些根本的
错误,至少第一眼看上去是这样的,你看出来了吗?考虑下面的语句
IntArray array;
int array_size = array.size();
还有
// 假设_size 是public 的
int array_size = array._size;
将array_size 初始化为数组的维数,但是很显然第一个例子需要一个函数调用而第
二个只需直接访问内存就行了,一般来说,函数调用比直接访问内存的开销要大得多,因而
信息隐藏是否给程序的执行效率增加了严重的额外负担,或许是阻碍性的负担呢?幸运的是
在一般情况下回答是不。
C++提供的解决方案是内联函数inline function 机制,内联函数在它的调用点上被展
开。一般来说,内联函数不会引入任何函数调用,例如在for 循环的条件子句中的size()
调用for ( int index = 0; index < array.size(); ++index )
// ...
并没有真的被调用_size 次而是在编译期间被内联扩展为下面的一般形式
// array.size()的内联扩展
for ( int index = 0; index < array._size; ++index)
// ...
在类定义中被定义的成员函数如size() 会被自动当作是内联函数,此外我们也可以
用inline 关键字显式地要求一个函数被视为内联函数。
到目前为止,我们已经提供了IntArray 类所要求的操作前面的14项,但是还没有
提供初始化机制和数组中单个元素的访问方式,
程序设计中的一个常见错误是使用事先并没向被正确初始化的对象,实际上这是一个
极为常见的错误,所以C++为用户定义的类提供了一种自动初始化机制类构造函数class
constructor
构造函数是一种特殊的类成员函数,专门用于初始化对象,如果构造函数被定义了,那
么在类的每个对象第一次被使用之前,这构造函数就被自动应用在对象上,构造函数由谁来
定义呢?类的提供者——也就是我们来定义构造函数为一个类,确定必要的构造函数是程序
设计不可缺少的一部分。
为了定义一个构造函数,我们只要给它与类相同的名字即可,另外我们不能给构造函
数指定返回值,但是可以给类定义多个构造函数,尽管它们都具有相同的名字但只要编译
器能够根据参数表区分它们就行。
更一般地,C++支持被称为函数重载function overloading 的机制,函数重载允许两个
或更多个函数使用同一个名字,限制条件是它们的参数表必须不同,参数类型不同或参数
的数目不同,根据不同的参数表,编译器就能够判断出对某个特定的调用应该选择哪一个
版本的重载函数。下面是一组合法的min()重载函数,这些函数也可以是类成员函数
// 一组min()重载函数
// 每个函数都有一个特有的参数表
#include <string>;
int min( const int *pia, int size );
int min( int, int );
int min( const char *str );
char min( string );
string min( string, string );