友元 friend

1. private 修饰成员问题

private 修饰成员内容,有且只能在类内使用,类外和子类都无法使用。成员函数如果是 private 修饰,通常情况下是内置函数或者辅助函数。成员变量 private 修饰,通常是为了限制当前成员变量的外部操作方式,降低错误使用的概率。

【private 修饰的成员内容类外操作受限】

2. friend 友元函数

2.1 单一类友元函数
#include <iostream>

using namespace std;

template <typename K, typename V>
class Data
{
public:
    Data() {};
    Data(K key, V value) : key(key), value(value) {}
    Data(const Data &data) : key(data.key), value(data.value) {}
    ~Data() {}

    void set_key(K key) { this->key = key; }
    K get_key() { return key; }

    void set_value(V value) { this->value = value; }
    V get_value() { return value; }

    /*
    当前 show_data 函数是一个友元函数,使用 friend 关键字修饰
    当前函数所需参数类型为 Data<K, V>,根据带有模版类的数据类型
    分析
        当前函数限制参数外部类型为 Data 类型
        内部类型尚未做任何的限制。模版对应类型由提供的实际参数
        Data 对应模版类型决定。

    【注意】
        友元函数有且只在类内定义,告知编译器,当前函数是哪一个类
        的友元函数,实现在类外部。
        并且,友元函数不属于任何一个类。
    【问题】
        friend void show_data(const Data<K, V> &data);
        当前 show_data 函数使用的模版是 Data 类声明的模版
        因为 show_data 不属于 Data 类内,在外部进行函数实现
        时,对应的模版 K V 无法再次使用。

    【解决】
        函数自行声明模版需求。
        函数自行定义模版需求对应 K1 和 V1,和当前 Data 类型
        模版没有任何的相关性。
    */
    template <typename K1, typename V1>
    friend void show_data(const Data<K1, V1> &data);

private:
    K key;
    V value;
};

template <typename K1, typename V1>
void show_data(const Data<K1, V1> &data)
{
    /*
    因为 show_data 是 Data 类型的友元函数,所以
    Data 类型认为 show_data 是自己的朋友,会对朋友
    开放整个类的所有权限。

    可以通过参数 Data 引用直接操作类内的所有成员内容,包括
    private 和 protected 限制的类外无法访问内容。
    */
    cout << "Key : " << data.key
         << ", Value : " << data.value
         << endl;
}

int main(int argc, char const *argv[])
{

    Data<string, int> data("煎饼果子", 10);

    cout << "Key : " << data.get_key()
         << ", Value : " << data.get_value()
         << endl;

    show_data(data);

    return 0;
}
2.2 多类友元函数
#include <iostream>

using namespace std;

/*
前置声明,告知编译器,当前 Type_B 类存在,可以优先编译使用
后续内容存在 Type_B 类相关内容。

之所以需要完成对应的前置声明操作,是因为在 Type_A 类中,使用了
后续类型 Type_B,数据类型前置声明手段。
*/
class Type_B;

class Type_A
{
public:
    Type_A() {}
    Type_A(int test_a) : test_a(test_a) {}
    Type_A(const Type_A &t) : test_a(t.test_a) {}

    friend void show_data(Type_A &t1, Type_B &t2);

private:
    int test_a;
};

class Type_B
{
public:
    Type_B() {}
    Type_B(int test_b) : test_b(test_b) {}
    Type_B(const Type_B &t) : test_b(t.test_b) {}

    friend void show_data(Type_A &t1, Type_B &t2);

private:
    int test_b;
};

void show_data(Type_A &t1, Type_B &t2)
{
    cout << "Type_A : " << t1.test_a
         << ", Type_B : " << t2.test_b
         << endl;
}

int main(int argc, char const *argv[])
{
    Type_A ta(10);
    Type_B tb(200);

    show_data(ta, tb);
    return 0;
}

3. 友元类

3.1 单向友元

A 类是 B 类的友元类,B 类对 A 类开放所有的成员内。

#include <iostream>

using namespace std;

class Type_B;

class Type_A
{
public:
    /*
    void show_type_b(Type_B &tb)
    {
        cout << "MSG : " << tb.msg << endl;
        tb.test();
    }
    如果按照当前代码进行编译操作,编译器提示
        03-单向友元类.cpp: In member function ‘void Type_A::show_type_b(Type_B&)’:
        03-单向友元类.cpp:13:29: error: invalid use of incomplete type ‘class Type_B’
            cout << "MSG : " << tb.msg << endl;
    【解释】
        当前代码中,确实完成 Type_B 类型前置声明,但是对于编译器而言 Type_B 是一个尚未
        完成的类型。但是 show_type_b 函数内部,需要完成对于 Type_B 类型的内容使用。在
        当前阶段,无法实现,所以语法报错

    【解决】
        按照开发的基本要求,声明和实现为分离状态 show_type_b 函数在整个 Type_B 类明确
        完成声明的情况下,才可以实现对应的函数,将函数实现放在 Type_B 声明,完成之后。
    */

    void show_type_b(Type_B &tb);
};

class Type_B
{
public:
    Type_B() {}
    Type_B(string msg) : msg(msg) {}
    Type_B(const Type_B &tb) : msg(tb.msg) {}
    ~Type_B() {}

    /*
    在当前 Type_B 类中,声明了 Type_A 是当前类的友元类
    Type_B 对 Type_A 开放所有内容
    */
    friend class Type_A;

private:
    string msg;

    void test()
    {
        cout << "Hi~ o(* ̄▽ ̄*)ブ,朋友~~~" << endl;
    }
};

void Type_A::show_type_b(Type_B &tb)
{
    cout << "MSG : " << tb.msg << endl;

    tb.test();
}

int main(int argc, char const *argv[])
{
    Type_B tb("回答我!");

    Type_A ta;

    ta.show_type_b(tb);

    return 0;
}
3.2 双向友元自行研究