二、友元
前面已经说过了,私有数据成员不能被类外的其他函数读取,但是有时候类会允许一些特殊的函数直接读写其私有数据成员。
关键字friend可以让特定的函数或者别的类的所有成员函数对私有数据成员进行读写。这既可以维护数据的私有性,有可以保证让特定的类或函数能够直接访问私有数据。
1.友元类
一个类可以声明另一个类为其友元,这个友元的所有成员函数都可以读写它的私有数据。
#include iostream.h
class Date;
class CustomDate
{
int da,yr;
public:
CustomDate(int d=0,int y=0) { da=d; yr=y; }
void display() const {cout< friend Date; //这儿
};
class Date
{
int mo,da,yr;
public:
Date(int m,int d,int y) { mo=m; da=d; yr=y; }
operator CustomDate();
};
Date::operator CustomDate()
{
static int dys[] = {31,28,31,30,31,30,31,31,30,31,30,31};
CustomDate cd(0, yr);
for (int i=0;i cd.da+=da;
return cd;
}
int main()
{
Date dt(11,17,89);
CustomDate cd(dt);
cd.display();
return 0;
}
在上面的程序中,有这样一句 friend Date; 该语句告诉编译器,Date类的所有成员函数有权访问CustomDate类的私有成员。因为Date类的转换函数需要知道CustomDate类的每个数据成员,所以真个Date类都被声明为CustomDate类的友元。
2.隐式构造函数
上面程序对CustomDate的构造函数的调用私有显示该类需要如下的一个转换构造函数:
CustomDate(Date& dt);
但是唯一的一个构造函数是:CustomDate(int d=0;int y=0);
这就出现了问题,编译器要从Date对象构造一个CustomDate对象,但是CustomDate类中并没有定义这样的转换构造函数。不过Date类中定义了一个成员转换函数,它可以把Date对象转换成CustomDate对象。于是编译器开始搜索CustomDate类,看其是否有一个构造函数,能从一个已存在的CustomDate的对象创建新的CustomDate对象。这种构造函数叫拷贝构造函数。拷贝构造函数也只有一个参数,该参数是它所属的类的一个对象,由于CustomDate类中没有拷贝构造函数,于是编译器就会产生一个默认的拷贝构造函数,该函数简单地把已存在的对象的每个成员拷贝给新对象。现在我们已经知道,编译器可以把Date对象转换成CustomDate对象,也可以从已存在的CustomDate对象生成一个新的CustomDate对象。那么上面提出的问题,编译器就是这样做的:它首先调用转换函数,从Date对象创建一个隐藏的、临时的、匿名的CustomDate对象,然后用该临时对象作为参数调用默认拷贝构造函数,这就生成了一个新的CustomDate对象。
3.预引用
上面的例子中还有这样一句 class Date;
这个语句叫做预引用。它告诉编译器,类Date将在后面定义。编译器必须知道这个信号,因为CustomDate类中引用了Date类,而Date里也引用了CustomDate类,必须首先声明其中之一。
使用了预引用后,就可以声明未定义的类的友元、指针和引用。但是不可以使用那些需要知道预引用的类的定义细节的语句,如声明该类的一个实例或者任何对该类成员的引用。
4.显式友元预引用
也可以不使用预引用,这只要在声明友元的时候加上关键自class就行了。
#include iostream.h
class CustomDate
{
int da,yr;
public:
CustomDate(int d=0,int y=0) { da=d; yr=y; }
void display() const {cout< friend class Date; //这儿,去掉前面的预引用
};
class Date
{
... ...
};
Date::operator CustomDate()
{
... ...
}
int main()
{
... ...
}
全国职称计算机考试速成过关系列套装:W .. 定价:¥133 优惠价:¥133.0 更多书籍 | |
全国职称计算机考试速成过关系列套装:W .. 定价:¥124 优惠价:¥124.0 更多书籍 |