[C++] 友元函数和友元类

c++中对类的访问通过访问修饰符进行控制,类对象不能访问privateprotected(子类中可以)修饰的变量和函数。有时候这种限制过于严格,因此,C++提供了另一种形式的访问权限——友元。

1.友元函数

通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。可以将友元理解为“类的好朋友”。简单来说,一个类的友元可以访问其私有属性和方法。

1.2.创建友元函数

  • Step1.创建友元函数时,首先在类中定义友元函数的原型,定义时必须加关键字friend:
friend void func();
  • Step2.在类的外部实现函数定义,在实现函数定义时,由于不是成员函数,因此不需要使用作用域解析符,同时不需要friend:
void func()
{
    ......
}

1.3.友元函数使用场景

当需要为类重载二元运算符时,就需要使用友元函数来实现。如常见的重载<<运算符:

//Time2.h
#include <iostream>
class Time
{
    //......
    public:
        friend std::ostream & operator<<(std::ostream &os,const Time & t);
};

//Time2.cpp
std::ostream & operator<<(std::ostream &os,const Time &t) {
    os << t.hour << "h" << t.minute << "m" << std::endl;
    return os;
}

2.友元类

除了让函数成为类的友元之外,还可以将类作为友元。

如果将A类声明为B类的友元类,则A类的所有方法都可以访问B类的私有成员和保护成员。

2.1.声明一个友元类

给一个类声明一个友元类时,使用friend 关键字,如:

class B
{
private:
    int age;
    friend class A;
};

class A
{
    void set_age(B &b,int t){b.age = t;}
};

此时A类将成为B类的友元类,这也意味着B类中的所有私有成员都可以在A类中访问.

2.2.作用

友元类的所有方法都可以访问原始类的私有成员和保护成员。

2.3.友元成员函数

可以让一个类的成员函数称为另一个类的友元,但使用友元成员函数时,必须要注意类的声明和定义顺序。下面我们一步步来看如何声明定义。

首先按照传统方式:

class B
{
private:
    int age;
    //成员友元函数
    friend void A::set_age(B &b,int t);
};

class A
{
    void set_age(B &b,int t){b.age = t;}
};

然而,当编译到友元成员函数时,由于A类没有声明,因此编译失败。所以这种方式不可取,那么采用第二种方式,我们先声明A类:

class A
{
    void set_age(B &b,int t){b.age = t;}
};

class B
{
private:
    int age;
    //成员友元函数
    friend void A::set_age(B &b,int t);
};

当编译器执行到set_age()函数时,由于没有定义B类,因此也将编译失败,所以这种方式也不可取。

对于这种场景,需要使用前向声明(Forward declaration).

class B;
class A
{
    //void set_age(B &b,int t){b.age = t;}
    void set_age(B &b,int t);
};

class B
{
private:
    int age;
    //成员友元函数
    friend void A::set_age(B &b,int t);
};

inline void A::set_age(B &b,int t){b.age = t;}

从这个例子中也看出,如果需要继续使用内联函数,则需要在类声明完成后显式使用inline关键字定义。由于B类使用了前向声明,但实际上还未声明,因此不能在友元函数中直接使用B类成员或函数,所以,set_age()只进行声明,而将定义放在B类声明之后。

最后来对友元成员函数的设计进行下总结:

假设需要A类成员函数作为B类的友元:

  • 1.首先前向声明B类;
  • 2.其次声明A类,并声明成员函数,但不能定义成员函数;
  • 3.接下来定义B类,包括对于A类成员函数的友元声明;
  • 4.最后定义A类成员函数,此时他才可以使用B累的成员。

让整个类成为友元不需要前向声明,是因为友元语句本身已经指出它是一个类。

2.4.函数重载和友元

如果一个类想把一组重载函数声明为它的友元,则需要对这组函数中的每个函数分别声明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值