在不放弃私有数据安全性的情况下, 使得类外部的函数或类能够访问类中的私有成员,在 C + + 中就用友元作为实现这个要求的辅助手段。
友元既可以是不属于任何类的一般函数,也可以是另一个类的成员函数, 还可以是整
个的一个类(这样, 这个类中的所有成员函数都可以成为友元函数)。
友元函数不是当前类的成员函数,而是独立于当前类的外部函数, 但它可以访问该类的所有对象的成员,包括私有成员和公有成员。
在类定义中声明友元函数时, 需在其函数名前加上关键字 friend。此声明可以放在公有部分,也可以放在私有部分。友元函数可以定义在类内部, 也可以定义在类的外部。
#include
#include
using namespace std;
class girl
{
char * name;
int age;
public:
girl( char * n, int d)
{
name = new char[strlen( n) + 1 ] ;
strcpy( name, n) ;
age = d;
}
friend void disp( girl & ) ;
// 声明友元函数
girl( )
{
delete name;
}
} ;
void disp(girl &x) // 定义友元函数
{
cout << "girl \ ′s name is:"<< x .name <<", age:"<< x .age << "\ n";
}
int main( )
{
girl e("Chen Xingwei", 18) ;
disp( e ) ;
// 调用友元函数
return 0;
}
程序的运行结果如下:
girl′s name is: Chen Xingwei , age: 18
从上面的例子可以看出,友元函数可以访问类对象的各个私有数据。若在类 girl 的声明中将友元函数的声明语句去掉,那么函数 disp ( ) 对类对象的私有数据的访问将变为非法的。
例如有 boy 和 girl 两个类,现要求打印出所有的男生和女生的名字和年龄, 我们只需一个独立的函数 prdata ( ) 就能够完成, 但它必须同时定义为这两个类的友元函数。
# include
# include
using namespace std;
class boy;
// 向前引用
class girl
{
char name [25];
int age;
public:
void init( char N[], int A);
friend void prdata( const girl plg, const boy plb);
// 声明函数 prdata()
};
void girl::init( char N[], int A)
{
strcpy( name, N);
age = A;
}
class boy
{
char name[25];
int age;
public:
void init( char N[], int A);
friend void prdata ( const girl plg, const boy plb);
// 声明函数 prdata()
};
void boy::init( char N[], int A)
{
strcpy( name, N);
age = A;
}
int main()
{
girl G1, G2, G3;
boy B1, B2, B3;
G1.init("Stacy", 12 );
G2.init("Judith", 13 );
G3.init("Leah", 12 );
B1.init("Jim", 11 );
B2.init("Michael", 13);
B3.init("Larry", 12 );
prdata (G1, B1 );
// 调用友元函数 prdata( )
prdata (G2, B2 );
// 调用友元函数 prdata( )
prdata (G3, B3 );
// 调用友元函数 prdata( )
return 0 ;
}
void prdata ( const girl plg, const boy plb ) // 定义友元函数 prdata()
{
cout << "name:"<< plg .name << "\n";
cout << "age:"<< plg .age <<"\n";
cout << "name:"<< plb .name << "\n";
cout << "age:"<< plb .age << "\n";
}
程序运行结果如下:
name: Stacy
age :12
name:Jim
age :11
name:Judith
age :13
name: Michael
age :13
name: Leah
age :12
name: Larry
age :12
程序中的第 3 行是由于第 9 行的要求而存在的。因为友元函数带了两个不同的类的对象,其中一个是类 boy 的对象, 而类 boy 要在晚一些时候才被声明。为了避免编译时的错误,编程时必须通过向前引用( forward reference ) 告诉 C + + 类 boy 将在后面定义在向前引用类声明之前,可以使用该类声明参数, 这样第 9 行就不会出错了。
prdata( )是程序中的一个独立函数, 可以被 main( ) 或其它任意函数调用。但由于它被定义成类 boy 和类 girl 的友元函数, 所以它能够访问这两个类中的私有数据。
除了一般的函数可以作为某个类的友元外, 一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的私有成员和公有成员, 还可以访问 friend 声明语句所在类对象中的私有成员和公有成员, 这样能使两个类相互合作、协调工作,完成某一任务。
# include
# include
using namespace std;
class girl;
class boy
{
char * name;
int age;
public:
boy( char * n, int d)
{
name = new char[strlen( n) + 1 ] ;
strcpy( name, n) ;
age = d;
}
void disp( girl & ) ;
// 声明 disp( )为类 boy 的成员函数
~boy()
{
delete name;
}
} ;
class girl
{
char * name;
int age ;
public:
girl( char * n, int d)
{
name = new char[strlen( n) + 1] ;
strcpy( name, n) ;
age = d;
}
friend void boy::disp( girl & ) ;
// 声明类 boy 的成员函数 disp()为类 girl 的友元函数
~girl()
{
delete name;
}
} ;
void boy::disp( girl &x ) // 定义友元函数 disp()
{
cout << "boy \ ′s name is:"<< name << ", age:"<< age << "\n";// 访问本类对象成员
cout << "girl \ ′s name is:"<< x .name <<", age:"<< x .age << "\ ";// 访问友类对象成员
}
int main()
{
boy b("chen hao", 25 ) ;
girl e("zhang wei ", 18 ) ;
b .disp( e ) ;
}
程序运行结果如下:
boy′s name is: chen hao , age : 25
girl′s name is: zhang wei , age: 18
一个类的成员函数作为另一个类的友元函数时, 必须先定义这个类。例如例中, 类 boy 的成员函数为类 girl 的友元函数,必须先定义类 boy。并且在声明友元函数时,要加上成员函数所在类的类名, 如:
friend void boy∷disp( girl & ) ;
程序中第 3 行“class girl;”为向前引用,因为函数 disp( ) 中将 girl & 作为参数, 而 girl在要晚一些时候才被定义。
不仅函数可以作为一个类的友元, 一个类也可以作为另一个类的友元。这种友元类的说明方法是在另一个类声明中加入语“friend 类名( 即友元类的类名) ;”, 此语句以放在公有部分也可以放在私有部分,例如:
class Y
{
// …
} ;
class X
{
// …
friend Y;
// 声明类 Y 为类 X 的友元类
// …
} ;
当一个类被说明为另一个类的友元时,它的所有的成员函数都成为另一个类的友元函数,这就意味着作为友元的类中的所有成员函数都可以访问另一个类中的私有成员。
下面的例子中,声明了两个类 boy 和 girl,类 boy 声明为类 girl 的友元,因此类 boy 的成员函数都成为类 girl 的友元函数,它们都可以访问类 girl 的私有成员。
#include
#include
using namespace std;
class girl;
class boy
{
char * name;
int age;
public:
boy( char * n, int d)
{
name = new char[strlen( n) + 1 ] ;
strcpy( name, n) ;
age = d;
}
void disp( girl & ) ;
// 声明 disp( 为类 boy 的成员函数
~boy( )
{
delete name;
}
} ;
class girl
{
char * name;
int age ;
friend boy;
// 声明类 boy 是类 girl 的友元
public:
girl( char * n, int d)
{
name = new char[strlen( n) + 1] ;
strcpy( name, n) ;
age = d;
}
~girl( )
{
delete name;
}
} ;
void boy::disp( girl &x ) // 定义函数 disp( )为类 boy 的成员函数,
// 也是类 girl 的友元函数
{
cout << "boy \′s name is:"<< name << ", age:"<< age << "\n";
cout << "girl \′s name is:"<< x .name <<", age:"<< x .age << "\n";
}
int main()
{
boy b("chen hao", 25 );
girl e("zhang wei ", 18 );
b.disp( e );
return 0;
}
程序运行结果如下:
boy′s name is: chen hao , age : 25
girl′s name is: zhang wei , age: 18
友元关系是单向的,不具有交换性。若类 X 是类 Y 的友元(即在类 Y 定义中声明 X 为 friend 类) , 类 Y 是否是 X 的友元,要看在类中是否有相应的声明。友元关系也不具有传递性,若类 X 是类 Y 的友元, 类 Y 是类 Z 的友元, 不一定类 X 是类 Z 的友元。