• c++ 友元函数 友元类


    1. 友元函数

    1.1 简介

    友元函数是在类的声明中声明的非成员函数,它被授予访问类的私有成员的权限。这意味着友元函数可以访问类的私有成员变量和私有成员函数,即使它们不是类的成员。
    一个类中,可以将其他类或者函数声明为该类的友元,使得这些友元函数能够访问该类的私有成员和受保护成员。

    1.2 特点

    1. 友元函数可以直接访问类的私有成员和受保护成员,包括私有成员变量和私有成员函数,无需通过对象或者类的接口来访问。
    2. 友元函数在声明时需要在类内部进行声明,并使用关键字 friend 进行修饰。但它不是类的成员函数,因此它在类的作用域之外定义和实现
    3. 友元关系是单向的:如果A是B的友元,那么B不一定是A的友元。
    4. 不继承权限,友元函数的权限仅限于声明它的类,而不会被派生类继承。

    1.3 使用场景

    1. 访问私有成员
      当需要在某个外部函数中直接访问一个类的私有成员时,可以将该函数声明为友元函数。
    #include 
    
    class MyClass {
    private:
        int privateData;
    
    public:
        MyClass(int data) : privateData(data) {}
    
        friend void printPrivateData(const MyClass& obj);
    };
    
    void printPrivateData(const MyClass& obj) {
        std::cout << "Private data: " << obj.privateData << std::endl;
    }
    
    int main() {
        MyClass obj(42);
        printPrivateData(obj);  // 调用友元函数访问私有成员
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. 实现操作符重载
    #include 
    
    class Complex {
    private:
        double real;
        double imaginary;
    
    public:
        Complex(double r, double i) : real(r), imaginary(i) {}
    
        friend std::ostream& operator<<(std::ostream& os, const Complex& obj);
    };
    
    std::ostream& operator<<(std::ostream& os, const Complex& obj) {
        os << obj.real << " + " << obj.imaginary << "i";
        return os;
    }
    
    int main() {
        Complex c(3.5, 2.5);
        std::cout << "Complex number: " << c << std::endl;  // 使用友元函数重载输出操作符
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    声明了一个友元函数operator<<,用于重载输出操作符<<,以便能够以自定义的方式打印Complex类的对象。在main函数中,我们创建了一个Complex对象c,并使用std::cout和友元函数operator<<来打印该对象的值。
    3. 提供类之间的非成员函数接口
    如果两个类之间需要共享信息或者互相调用对方的非公开成员,可以使用友元关系

    #include 
    
    class ClassB;
    
    class ClassA {
    private:
        int data;
    
    public:
        ClassA(int d) : data(d) {}
    
        friend void processData(const ClassA& objA, const ClassB& objB);
    };
    
    class ClassB {
    private:
        int data;
    
    public:
        ClassB(int d) : data(d) {}
    
        friend void processData(const ClassA& objA, const ClassB& objB);
    };
    
    void processData(const ClassA& objA, const ClassB& objB) {
        std::cout << "Data from ClassA: " << objA.data << std::endl;
        std::cout << "Data from ClassB: " << objB.data << std::endl;
    }
    
    int main() {
        ClassA objA(42);
        ClassB objB(24);
        processData(objA, objB);  // 调用友元函数处理两个类的数据
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    定义了两个类ClassA和ClassB,并在它们之间声明了一个友元函数processData。这个函数可以访问ClassA和ClassB的私有成员变量,并在函数中处理这些数据。在main函数中,我们创建了一个ClassA对象objA和一个ClassB对象objB,然后调用友元函数processData来处理这两个类的数据。

    1.4 注意

    1. 友元关系破坏了封装性原则,因此应谨慎使用。过度依赖友元关系可能会导致代码不易维护和扩展。
    2. 友元关系没有继承性质,只限于被声明为友元的类或者函数能够访问相应的成员。

    2. 友元类

    2.1 简介

    C++中的友元类(friend class)是指一个类可以将另一个类声明为友元,从而允许友元类访问其私有成员。

    2.2 特点

    1. 友元关系是单向的:如果类A是类B的友元,则只有类B能够访问类A的私有和保护成员,反之则不成立。
    2. 友元关系不可传递:即使类A是类B的友元,而类B又是类C的友元,但并不能推导出类A是类C的友元。
    3. 友元关系没有继承性:即使派生类继承了基类,基类中声明为友元的其他类并不会自动成为派生类的友元。

    2.3 使用场景

    1. 信息封装:当一个类需要将其私有成员暴露给另一个类以实现特定功能时,可以将另一个类声明为友元类。这样,友元类就可以直接访问声明它的类的私有成员,从而实现类之间的信息封装。
    2. 成员访问优化:有时候,多个类之间需要频繁访问彼此的私有成员,而不希望通过公有接口进行访问。在这种情况下,可以将这些类声明为友元类,以提高成员访问的效率。

    代码:

    class FriendClass {
    private:
        int privateData;
    
    public:
        FriendClass(int data) : privateData(data) {}
    
        friend class MyClass;
    };
    
    class MyClass {
    public:
        void accessFriendData(const FriendClass& obj) {
            int data = obj.privateData;  // 友元类可以访问FriendClass的私有成员
        }
    };
    
    int main() {
        FriendClass obj(42);
        MyClass myObj;
        myObj.accessFriendData(obj);  // MyClass通过友元类访问FriendClass的私有成员
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    上述示例中,定义了两个类FriendClass和MyClass。FriendClass将MyClass声明为友元类,从而允许MyClass访问FriendClass的私有成员变量privateData。在MyClass中,我们定义了一个成员函数accessFriendData,它通过友元类的权限访问FriendClass的私有成员。在main函数中,创建了FriendClass的对象obj和MyClass的对象myObj,并通过myObj调用accessFriendData来访问FriendClass的私有成员。

    两个代码互为友元,代码:

    #include 
    
    using namespace std;
    
    class B; // 前向声明
    
    class A {
    private:
        int privateDataA;
    public:
        A() : privateDataA() {};
    
        friend class B; // 声明B为A的友元类
    
        void displayPrivateData(const B& b);
    };
    
    class B {
    private:
        int privateDataB;
    public:
        B() : privateDataB(10) {};
    
        friend class A; // 声明A为B的友元类
    
        void setPrivateData( A & a, int data) {
            a.privateDataA = data; // 可以直接访问A中的私有成员
            cout << "Successfully set private data of A from B: " << a.privateDataA << endl;
        }
    };
    
    void A::displayPrivateData(const B & b) {
        cout << "Accessing private data of B from A: " << b.privateDataB << endl;
    }
    
    int main() {
        A a;
        B b;
    
        b.setPrivateData(a, 42); // 通过B类的成员函数修改A类的私有成员数据
        a.displayPrivateData(b); // 通过A类的成员函数访问B类的私有成员数据
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    运行结果:

    Successfully set private data of A from B: 42
    Accessing private data of B from A: 10
    
    • 1
    • 2

    A和B是两个类。通过将彼此声明为友元类,它们可以直接访问对方的私有成员。在主函数中,我们创建了一个A对象a和一个B对象b,并使用友元函数setPrivateData从b中修改了a的私有成员数据,并使用友元函数displayPrivateData从a中访问了b的私有成员数据。

  • 相关阅读:
    fastadmin with 和 filed 合用导致field失效
    [极致用户体验] 我做的《联机五子棋》是如何追求极致用户体验的?(上)
    React Native 的手势和触摸事件
    【MTK】 Reset key 支持系统重启
    椭圆曲线点加的应用计算
    干货 | RDBMS 索引类型概述
    数据结构-难点突破(C++/Java详解实现串匹配算法KMP,next数组求法,KMP算法优化nextval数组)
    gradle版本是7.1.3加载arr包踩坑
    基于微信小程序的电影院票务系统设计与实现-计算机毕业设计源码+LW文档
    RecyclerView 数据更新方法 notifyItemChanged/notifyItemInsert/notifyIteRemoved
  • 原文地址:https://blog.csdn.net/weixin_40378209/article/details/133805689