再上一篇:11.3 冲突、支配规则和赋值兼容性
上一篇:11.4 虚基类
主页
下一篇:12.2 虚函数
再下一篇:12.3 静态成员
文章列表

第十二章 类的其它特性

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

本章介绍类的友元函数、虚函数、静态成员、const对象和volatile对象以及指向类成员的指针。

12.1友元函数

从前面章节已经介绍的内容可以知道,当把类中的成员的访问权限定义为私有的或保护的时,在类的外面,只能通过该类的成员函数来访问这些成员。这是由类的封装性所确定的。这种用法往往觉得不够方便,若把类的成员的访问权限均定义为公有的访问权限时,又损害了面向对象的封装性。为此,在C++中提供了友元函数,允许在类外访问类中的任何成员(私有的、保护的或公有的)。

12.1.1 友元函数的说明及使用

在定义一个类时,若在类中用关键字 friend修饰函数,则该函数就成为该类的友元函数,它可以访问该类中的所有成员。说明一个友元函数的一般格式为:

friend FuncName();

例12.1 用友元函数的方法求圆柱体的体积。

#include

const float PI =3.1415926;

class A{

float r ;

float h;

public:

A(float a,float b){r=a; h=b;}

float Getr(){return r;}

float Geth(){return h;}

friend float Volum( A &);

};

float Volum( A &a)

{

return PI*a.r*a.r*a.h; //A

}

void main(void)

{

A a1(25,40),a2(10,40);

cout <<"圆柱体1的体积为:"<

cout <<"圆柱体2的体积为:"<

}

本例中把函数Volum()定义为类A的友元函数,在类A中给出了友元函数的原型说明,而在定义函数Volum()时并不像定义成员函数那样,在函数名前要加上作用域运算符::。从例中可以看出,计算圆柱体1的体积时,只要调用一次友元函数,而在求圆柱体2的体积时,调用三次a2的成员函数。前者的运行效率比后者要高一些。

有关友元函数的使用,说明以下几点:

1、友元函数不是类的成员函数

友元函数并不是对应类的成员函数,它不带有this指针,因此必须将对象名或对象的引用作为友元函数的参数,并在函数体中使用运算符“.”来访问对象的成员。如上例A行中用a.r来访问对象a的私有成员。友元函数与一般函数的不同点在于:友元函数必须在类的定义中说明,其函数体可在类内定义,也可在类外定义;它可以访问该类中的所有成员(公有的、私有的和保护的),而一般函数只能访问类中的公有成员。

2、在类中,对友元函数指定访问权限是无效的

正因为友元函数不是类的成员函数,所以它不受类中访问权限关键字的限制,可以把它放在类的私有部分,放在类的公有部分或放在类的保护部分,其作用都是一样的。换言之,在类中对友元函数指定访问权限是不起作用的。

3、友元函数的作用域

由于友元函数不是对应类的成员函数,所以它的作用域与成员函数不一样。友元函数的作用域与一般函数的作用域相同。如上例中的友元函数,具有全局作用域,可在程序中的任何位置调用它。

4、使用友元函数的目的是提高程序的运行效率

使用友元函数,可减少函数的调用次数,当然也就提高了程序的运行效率。可从上面的例子中明显看出这一点。

5、应该谨慎使用友元函数

由于友元函数破坏了类的封装性,它的使用一直是 C++程序设计领域中一个有争论的问题。一些程序设计人员认为友元函数是危险的,有可能造成对程序的破坏,并影响程序的可读性,可维护性和类的封装性。因此,在程序中不应该使用友元函数。另一些程序设计人员则认为,友元函数是一种有用的技术,如果正确使用则对程序不会造成破坏,是安全的。我们认为,应该谨慎使用友元函数,在许多场合下,它是一种方便使用类中私有成员或保护成员的工具,但如果操作失误,则是非常危险的。通常使用友元函数来取对象中的数据成员值,而不修改对象中的成员值,则肯定是安全的。

12.1.2 成员函数用作友元

一个类可以定义若干个友元函数,可以将一个类的任一个成员函数说明为另一个类的友元函数,以便通过这个成员函数访问另一个类中的成员。亦可以将一个类中的所有成员函数都说明为另一个类的友元函数。下面,分别用例子来说明把成员函数定义为友元的方法及其使用。

例12.2 将一个类的成员函数用作另一外类的友元函数。

#include

class B; //D

class A{

float x ,y;

public:

A(float a,float b){x=a; y=b;}

float Getx(){return x;}

float Gety(){return y;}

void Setxy( B & ); //E

};

class B{

float c,d;

public:

B(float a,float b) {c=a;d=b;}

float Getc(){return c;}

float Getd(){return d;}

friend void A::Setxy( B &); //F

};

void A::Setxy(B &b)

{

x=b.c;y=b.d; //G

}

void main(void)

{

A a1(25,40);

B b1(55,66);

cout <<"a1.x="<var="<< GlobalF->var<<'\n';

delete GlobalF;

}

执行程序后输出以下2行:

x=500 y=500

GlobalF->var=1000

在上例中,将类F2作为类F的友元,使得类F2中的任一成员函数均可使用类F中的所有成员;并将函数MakeObj()和主函数main( )也作为类F的友元。

由于把类F的构造函数说明为私有的,所以在主函数main( )中产生类F的对象f时,若main( )不是类F的友元,则不允许访问类F的私有构造函数。换言之,在这种情况下只有类F的友元函数才能产生类F的对象。在函数MakeObj()中用new运算符为类F的对象申请一个动态的存储空间,并将其私有的成员赋值为1000。

在类F2的构造函数中,将类F的私有成员var的值作为类F2私有成员var2的初值。也只有将类F2作为类F的友元时,才能取到类F的私有成员。