友元

介绍

在C++中,友元(friend) 是一种特殊的访问控制机制,允许其他类或其他函数访问当前类的私有成员和保护成员。友元的主要目的是为了提供更灵活的访问权限,尤其是在需要多个类之间紧密合作的情况下。

友元类型

(1) 友元函数:一个普通的函数可以被声明为某个类的友元函数,这样它就可以访问该类的私有和保护成员。

class MyClass {  
private:  
    int data;  
public:  
    MyClass(int val) : data(val) {}  
    friend void showData(MyClass obj); // 声明友元函数  
};  

void showData(MyClass obj) {  
    std::cout << "Data: " << obj.data << std::endl; // 访问私有成员  
}

(2) 友元类:一个类可以被声明为另一个类的友元类,这样友元类的所有成员函数都可以访问该类的私有和保护成员。

class MyClass {  
private:  
    int data;  
public:  
    MyClass(int val) : data(val) {}  
    friend class FriendClass; // 声明友元类  
};  

class FriendClass {  
public:  
    void display(MyClass obj) {  
        std::cout << "Data: " << obj.data << std::endl; // 访问私有成员  
    }  
};

(3) 友元成员函数:一个类的成员函数可以被声明为另一个类的友元,这样该成员函数可以访问另一个类的私有和保护成员。

class MyClass {  
private:  
    int data;  
public:  
    MyClass(int val) : data(val) {}  
    friend void FriendClass::display(MyClass obj); // 声明友元成员函数  
};  

class FriendClass {  
public:  
    void display(MyClass obj) {  
        std::cout << "Data: " << obj.data << std::endl; // 访问私有成员  
    }  
};

友元特点和应用场景

  1. 不继承:友元关系不是继承关系,友元类或函数并不自动成为其他类的友元。
  2. 不对称:如果类A是类B的友元,类B并不一定是类A的友元。
  3. 访问权限:友元可以访问私有和保护成员,但友元本身并不是类的成员。
  4. 设计考虑:使用友元可以提高类之间的协作,但过度使用可能会导致代码的封装性降低,因此应谨慎使用

操作符重载:在重载某些操作符时,可能需要访问类的私有成员。

用法

友元 作用

友元是针对类来说的,友元可以让其他类或其他函数访问当前类的私有成员和保护成员

友元平常并不推荐使用,只要可以用友元写出必须用友元的重载运算符就可以了

友元 注意事项

(1) 友元会破坏封装性一般不推荐使用,所带来的方便写几个接口函数就解决了

(2) 某些运算符的重载必须用到友元的功能,这才是友元的真正用途

友元 相关代码

友元基本使用

#include <iostream>

class Test
{
    friend class Test2;                         // 声明Test2为友元类
    friend void output(const Test& test);       // 声明output函数为友元函数

public:
    Test() = default;
    ~Test() = default;
private:
    std::string name = "lisi";
    int age = 100;
};


// 另一个类访问私有成员
class Test2
{
public:
    Test2() {};
    ~Test2() {};

    void output(const Test& test) const  // 为了在Test2类里访问Test类的私有成员,在Test类里声明Test2为友元类
    {
        std::cout << "name = " << test.name << ", age = " << test.age << std::endl;
    }
};

// 另一个函数访问私有成员
void output(const Test& test)          // 为了在output函数里访问Test的私有成员,在Test类里声明output函数为友元函数
{
    std::cout << "name = " << test.name << ", age = " << test.age << std::endl;
}

int main()
{
    Test t1;
    Test2 t2;
    t2.output(t1);
    output(t1);
    return 0;
}

利用公共接口代替友元

#include <iostream>

class Test
{
public:
    Test() = default;
    ~Test() = default;

    // 要想其他的类或函数 访问私有成员,友元会破坏封装性
    // 最好的方式是直接多写一些公共接口就行了,也可以达到一样的效果,而且不破坏封装性
    std::string getName() const{ return name; }
    int getAge() const { return age; }

private:
    std::string name = "lisi";
    int age = 100;
};


// 另一个类访问私有成员
class Test2
{
public:
    Test2() {};
    ~Test2() {};

    void output(const Test& test) const
    {   // 使用公共接口访问
        std::cout << "name = " << test.getName() << ", age = " << test.getAge() << std::endl;
    }
};

// 另一个函数访问私有成员
void output(const Test& test)          
{
    // 使用公共接口访问
    std::cout << "name = " << test.getName() << ", age = " << test.getAge() << std::endl;
}

int main()
{
    Test t1;
    Test2 t2;
    t2.output(t1);
    output(t1);
    return 0;
}