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

2023-12-13 21:00:35

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

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;
}

运行结果:

文章来源:https://blog.csdn.net/m0_47324800/article/details/134979732
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。