C++面向对象(OOP)编程-友元(友元函数和友元类)

本文主要介绍面向对象编程的友元的使用,以及友元的特性和分类,提供C++代码。

🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:C/C++精进之路
🎀CSDN主页 发狂的小花
🌄人生秘诀:学习的本质就是极致重复!

目录

1 为什么引进友元

2 友元的性质

3 友元的本质

4 友元分类

4.1 全局函数为友元函数

4.2 类的成员函数为友元函数

4.3 类作为友元


1 为什么引进友元

        面向对象编程(OOP)的三大特性中的封装,是通过类实现对数据的隐藏和封装。一般定义类的成员变量为私有成员,成员函数为公有函数,通过公有函数作为类的接口实现与外部交互。一些情况下,类外的某些函数需要频繁访问类的成员变量,因此引入了友元的概念,将类外的函数定义为该类的友元函数,从而实现对该类私有成员的访问。由此,还引入友元类,就是一个类是另一个类的友元类,友元类可以访问另一个类的所有成员。友元函数和友元类称为友元。

        友元的作用是提高了程序的运行效率(减少了类型检查和安全检查的耗时),但是友元破坏了类的封装和隐藏性,让非类成员函数可以类的私有成员。 

        友元是C++语言中的一种关系,友元关系发生在函数与类之间或者类与类之间。友元关系是单向的,不能传递。

        与类有友元关系的函数称为友元函数,与类有友元关系的类称为友元类。

2 友元的性质

        (1)在被访问类中以friend关键字修饰友元类或者友元函数

        (2)友元不属于该类,且不受该类的访问限制,可以直接访问具体类的所有成员

        (3)友元关系不能被继承

        (4)友元关系是单向的,不具有交换性,只能是一个函数访问一个类的所有成员,或者一个类允许访问另一个类的所有成员,反之不行

        (5)友元关系不具有传递性

3 友元的本质

        友元的本质是提供不属于该类成员,包括全局函数、其他类的成员函数、其他类,访问本类所有成员和成员属性的属性。

4 友元分类

4.1 全局函数为友元函数

        全局函数拥有访问一个类所有成员的能力,需要在被访问类中用关键字friend声明f被访问类的友元函数。一个类可以拥有多个友元函数。一个函数也可以是多个类的友元函数。

代码如下:

#include <iostream>
#include <string>
using namespace std;

class A
{
    private:
        string name_;
        int age_;
    public:
        A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};
        virtual ~A()
        {
            cout << "A析构函数 " << endl;
        }
        void func()
        {
            std::cout << "A's func()" << std::endl;
        }

        
        friend void get_members_global(A & a);  // 友元全局函数,可以访问A的私有成员变量和所有的公有成员
        
};

// 全局函数作为友元函数
void get_members_global(A & a)
{
    cout << a.name_ << " is " << a.age_ << " years old " << endl;
    a.func();
}


int main()
{
    A a("Hubery",45);

    cout << "***************************全局函数作为友元函数***************************" << endl;

    get_members_global(a);

    return 0;
}

运行结果:

4.2 类的成员函数为友元函数

        类成员函数作为类的友元声明时只需在友元的名称前加上关键字friend,其格式如下:

friend 类型 类名::函数名(形式参数);

一个函数可以是多个类的友元函数,只需要在各个类中分别声明。

代码如下:

#include <iostream>
#include <string>
using namespace std;

class A;

class C
{
    public:
        //类的成员函数作为友元函数
        void get_members_member(A &a);
        C()
        {
            cout << "C构造函数" << endl;
        }
        ~C()
        {
            cout << "C析构函数" << endl;
        }
};

class A
{
    private:
        string name_;
        int age_;
    public:
        A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};
        virtual ~A()
        {
            cout << "A析构函数 " << endl;
        }
        void func()
        {
            std::cout << "A's func()" << std::endl;
        }

        friend void C::get_members_member(A &a); // C的成员函数做友元函数,可以访问所有成员
        
};

// 类的成员函数作为友元函数
void C::get_members_member(A &a)
{
    cout << a.name_ << " is " << a.age_ << " years old " << endl;
    a.func();
}

int main()
{
    A a("Hubery",45);
    C c;

    cout << "***************************类的成员函数作为友元函数***************************" << endl;

    c.get_members_member(a);

    return 0;
}

运行结果:

这里用到类的前向声明。前向声明,是一种不完全型(forward declaration)声明,即只需提供类名(无需提供类实现)即可。前向声明功能有限:
        (1)不能定义类的对象。
      (2)可以用于定义指向这个类型的指针或引用。
      (3)用于声明(不是定义)使用该类型作为形参或者返回类型的函数。

4.3 类作为友元

        友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以访问另一个类的私有成员、保护成员时,可以将该类声明为另一类的友元类。

定义友元类的语句格式如下:

friend class 类名;
friend和class是关键字,类名必须是程序中的一个已定义的类。

代码如下:

#include <iostream>
#include <string>
using namespace std;

class B; // 前向声明

class A
{
    private:
        string name_;
        int age_;
    public:
        A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};
        virtual ~A()
        {
            cout << "A析构函数 " << endl;
        }
        void func()
        {
            std::cout << "A's func()" << std::endl;
        }
        friend class B; // 声明B为A的友元类,B中成员函数可以访问A中所有的成员
        
};

class B
{
    private:
        string name_;
        int age_;
    public:
        B(const string name,const int age) : name_(name), age_(age) {cout << "B构造函数 初始化参数" << endl;};
        virtual ~B()
        {
            cout << "B析构函数 " << endl;
        }
        void func()
        {
            std::cout << "B's func()" << std::endl;
        };
        // 友元类
        void get_members_class(A & a)
        {
            cout << a.name_ << " is " << a.age_ << " years old " << endl;
            a.func();
        };

};


int main()
{
    A a("Hubery",45);
    B b("Tom",24);

    cout << "***************************友元类***************************" << endl;
    b.get_members_class(a);

    return 0;
}

运行结果:

🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!最后,☺祝愿大家每天有钱赚!!!

  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

发狂的小花

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

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

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

打赏作者

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

抵扣说明:

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

余额充值