友元

在不放弃私有数据安全性的情况下, 使得类外部的函数或类能够访问类中的私有成员,在 C + + 中就用友元作为实现这个要求的辅助手段。
友元既可以是不属于任何类的一般函数,也可以是另一个类的成员函数, 还可以是整
个的一个类(这样, 这个类中的所有成员函数都可以成为友元函数)。

友元函数

友元函数不是当前类的成员函数,而是独立于当前类的外部函数, 但它可以访问该类的所有对象的成员,包括私有成员和公有成员。
在类定义中声明友元函数时, 需在其函数名前加上关键字 friend。此声明可以放在公有部分,也可以放在私有部分。友元函数可以定义在类内部, 也可以定义在类的外部。

#include <iostream>
#include <string.h>
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 ( ) 对类对象的私有数据的访问将变为非法的。

说明:
  1. 友元函数虽然可以访问类对象的私有成员, 但它毕竟不是成员函数。因此,在类的外部定义友元函数时,不必像成员函数那样, 在函数名前加上“类名∷”。
  2. 友元函数一般带有一个该类的入口参数。因为友元函数不是类的成员, 所以它不能直接引用对象成员的名字,也不能通过 this 指针引用对象的成员, 它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员。
    例如上面例子中的友元函数 void disp( girl & x)就带有该类的一个入口参数。
  3. ) 当一个函数需要访问多个类时, 友元函数非常有用,普通的成员函数只能访问其所属的类,但是多个类的友元函数能够访问相应的所有类的数据。
  4. 友元函数通过直接访问对象的私有成员,提高了程序运行的效率。在某些情况下,如运算符被重载时, 需要用到友元(见第 5 章 )。但是友元函数破坏了数据的隐蔽性,降低了程序的可维护性,这与面向对象的程序设计思想是背道而驰的, 因此使用友元函数应谨慎。

例如有 boy 和 girl 两个类,现要求打印出所有的男生和女生的名字和年龄, 我们只需一个独立的函数 prdata ( ) 就能够完成, 但它必须同时定义为这两个类的友元函数。

# include<iostream>
# include<string.h>
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 <iostream>
# include <string.h>
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

说明:
  1. 一个类的成员函数作为另一个类的友元函数时, 必须先定义这个类。例如例中, 类 boy 的成员函数为类 girl 的友元函数,必须先定义类 boy。并且在声明友元函数时,要加上成员函数所在类的类名, 如:
    friend void boy∷disp( girl & ) ;

  2. 程序中第 3 行“class girl;”为向前引用,因为函数 disp( ) 中将 girl & 作为参数, 而 girl在要晚一些时候才被定义。

友元类

不仅函数可以作为一个类的友元, 一个类也可以作为另一个类的友元。这种友元类的说明方法是在另一个类声明中加入语“friend 类名( 即友元类的类名) ;”, 此语句以放在公有部分也可以放在私有部分,例如:

class Y
{
    // …
} ;
class X
{
    // …
    friend Y;
    // 声明类 Y 为类 X 的友元类
    // …
} ;

当一个类被说明为另一个类的友元时,它的所有的成员函数都成为另一个类的友元函数,这就意味着作为友元的类中的所有成员函数都可以访问另一个类中的私有成员。

下面的例子中,声明了两个类 boy 和 girl,类 boy 声明为类 girl 的友元,因此类 boy 的成员函数都成为类 girl 的友元函数,它们都可以访问类 girl 的私有成员。

#include <iostream>
#include <string.h>
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 的友元。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值