C++ 笔记(30)— 友元函数与友元类

我们知道类的私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦。

C++ 设计者认为, 如果有的程序员真的非常怕麻烦,就是想在类的成员函数外部直接访问对象的私有成员,那还是做一点妥协以满足他们的愿望为好,这也算是眼前利益和长远利益的折中。因此,C++ 就有了友元(friend)的概念。打个比方,这相当于是说:朋友是值得信任的,所以可以对他们公开一些自己的隐私。

友元分为两种:友元函数和友元类。

1. 友元函数

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

在定义一个类的时候,可以把一些函数(包括全局函数和其他类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对象的私有成员了。

将全局函数声明为友元的写法如下:

friend  返回值类型  函数名(参数表);

将其他类的成员函数声明为友元的写法如下:

friend  返回值类型  其他类的类名::成员函数名(参数表);

但是,不能把其他类的私有成员函数声明为友元函数。

示例代码如下:

#include <iostream>
using namespace std;

class Student
{
    public:
        Student(string i, string n, int a); // 简单的构造函数
        ~Student(); // 析构函数
        string getID();
        friend int getAge(Student stu); // 友元函数

    private:
        string id;
        string name;
        int age;
};


Student::Student(string i="", string n="", int a=0) 
{
    cout << "constructor func run" << endl;
    id = i;
    name = n;
    age = a;
}

Student::~Student()
{
    cout << "destructor func run" << endl;
}


string Student::getID()
{
    return id;
}

// getAge() 不是任何类的成员函数
int getAge(Student stu)
{
    //  因为 getAge() 是 Student 的友元函数,所以它可以直接访问该类的任何成员 */
    return stu.age;
}


int main() 
{
    Student stu ("0001", "Jack", 18);
    // 使用友元函数获取年龄
    int age = getAge(stu);
    cout << "age is " << age << endl;
    return 0;
}

输出结果:

constructor func run
destructor func run
age is 18
destructor func run

因为友元函数没有 this指针,则参数要有三种情况:

  • 要访问非 static成员时,需要对象做参数;
  • 要访问 static成员或全局变量时,则不需要对象做参数;
  • 如果做参数的对象是全局对象,则不需要对象做参数;
  • 可以直接调用友元函数,不需要通过对象或指针;

示例代码:

class INTEGER
{
    friend void Print(const INTEGER& obj);//声明友元函数
};

void Print(const INTEGER& obj)
{
    //函数体
}

void main()
{
    INTEGER obj;
    Print(obj);//直接调用
}

2. 友元类

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

一个类 A 可以将另一个类 B 声明为自己的友元,类 B 的所有成员函数就都可以访问类 A 对象的私有成员。在类定义中声明友元类的写法如下:

friend  class  类名;

示例代码:

#include <iostream>
using namespace std;

class Student
{
    public:
        Student(string i, string n, int a); // 简单的构造函数
        string getID();
        friend class Teacher; // 友元函数

    private:
        string id;
        string name;
        int age;
};

Student::Student(string i="", string n="", int a=0) 
{
    cout << "constructor func run" << endl;
    id = i;
    name = n;
    age = a;
}

class Teacher
{
    public:
        void checkStudent(Student stu);
};

void Teacher::checkStudent(Student stu)
{
    // Teacher 是 Student 的友元类,它可以直接访问 Student 类的任何成员
    cout << "sut.age is " << stu.age << endl;
    cout << "sut.name is " << stu.name << endl;
}

int main() 
{
    Student stu ("0001", "Jack", 18);
    Teacher t;
    t.checkStudent(stu);
    return 0;
}

输出结果:

constructor func run
sut.age is 18
sut.name is Jack

友元关系在类之间不能传递,即类 A 是类 B 的友元,类 B 是类 C 的友元,并不能导出类 A 是类 C 的友元。“咱俩是朋友,所以你的朋友就是我的朋友”这句话在 C++ 的友元关系上不成立,当然在现实生活中很大概率也是不能成立的。

我们使用了友元之后,发现在设计程序的时候方便了很多。原先的那些私有成员都能轻松地被访问了。于是我们不用去写那些繁琐的成员函数,程序执行的时候也减少了函数的调用次数,提高了运行效率。

友元的存在,破坏了类的封装性。一个类出现问题,就不仅仅是由这个类本身负责了,还可能和它众多的友元有关。这无疑使得检查调试的范围突然扩大了许多,难度也陡然增加。

所以,我们在使用友元的时候,权衡使用友元的利弊,使程序达到最佳的效果。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wohu007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值