• C++ 友元关系详解


    在C++中,在某些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍然阻止一般的访问,这是很方便做到的。例如,被重载的操作符,如输入或输出操作符,经常需要访问类的私有数据成员。这些操作符不可能为类的成员。然而,尽管不是类的成员,它们仍是类的“接口的组成部分”。

    而友元机制,允许一个类将对其非公有成员的访问权授予指定的函数或类。友元的声明以关键字 friend 开始。它只能出现在类定义的内部。友元声明可以出现在类中的任何地方:友元不是授予友元关系的那个类的成员,所以它们不受声明出现部分的访问控制影响。

    下面给出C++中所有有关友元的结论和限制,然后后面针对每个细节给出示例:

    1、友元关系:

    1.1将一个非成员函数reset()声明为类example的友元函数,使得该非成员函数可以访问类example的私有成员。

    class example; // 这里必须对类 example 做前向声明,否则下面的函数声明将报错

    void reset(example &e);

    class example

    {

    public:

    friend void reset(class example &e);

    private:

    int n;

    };

    // 该函数定义必须放在类 example 的后面,否则无法解析变量n

    void reset(example &e)

    {

    e.n = 0;

    }

    1.2 将类man声明为类woman的友元类,使得可以通过类man对象访问类woman的私有成员

    class woman; // 前向声明

    class man

    {

    public:

    void disp(woman &w);

    void reset(woman &w);

    };

    class woman

    {

    public:

    friend class man; // 将man设为woman的友元类,这样man对象的任何成员函数都可以访问woman的私有成员

    private:

    string name;

    };

    void man::disp(woman &w)

    {

    cout << w.name << endl;

    }

    void man::reset(woman &w)

    {

    w.name.clear();

    }

    1.3 将一个类Y的某成员函数声明为类X的友元函数,使得可以通过类Y的这个成员函数访问类X的私有成员。

    class woman; // 前向声明

    class man

    {

    public:

    void disp(woman &w);

    void reset(woman &w);

    };

    class woman

    {

    public:

    friend void man::disp(woman &w); // 将man的其中一个成员函数disp()设为woman的友元函数,就可以使用该函数访                                         // 问woman对象的私有成员了

    private:

    string name;

    };

    void man::disp(woman &w)

    {

    cout << w.name << endl;

    }

    // man的reset()成员函数不是woman类的友元函数,因此不能访问其私有成员

    /*

    void man::reset(woman &w)

    {

    w.name.clear();

    }

    */

    2、友元作用域

    注意到上面的示例代码,友元声明和友元定义之间的依赖关系:比如最后一个例子,由于woman类要声明man类中的成员函数disp为友元函数,因此必须将man类的定义放在woman之前。但是man类中又要对woman类中的数据成员进行操作,所以必须将disp函数的定义放在woman的后面。这个关系要搞清楚,否则编译不成功。

    3、友元跟重载函数的关系

    如果有多个重载函数的版本,那么可以将其中的一个或者几个设为某个类的友元。其他的函数不受此设置的影响,依然不能访问某类的私有数据成员。例如:

    #include <iostream>

    #include <string>

    #include <map>

    using namespace std;

    class screen;

    void show(const screen &s);

    void show(int, int, const screen &);

    class screen

    {

    public:

    screen():x(0.0), y(0.0){}

    friend void show(const screen &s);

    friend void show(int a, int b, const screen &s); // 如果将此行删除,将无法调用该版本的show函数

    private:

    float x;

    float y;

    };

    void show(const screen &s)

    {

    cout << s.x << ", " << s.y << endl;

    }

    void show(int a, int b, const screen &s)

    {

    cout << s.x + a << ", " << s.y + b << endl;

    }

    int main(void)

    {

    screen s;

    show(s);

    show(100, 200, s);

    string word;

    getline(cin, word);

    return 0;

    }

    4、友元跟权限标识符的关系

    实际上,一个类的友元,不管是友元类、友元成员函数还是友元非成员函数,都必须是public访问权限的,否则无法在类外被调用。

  • 相关阅读:
    [archlinux][plasma][screensaver] plasma5配置屏保程序,没成功(-_-#)
    [skill][https][ssl/tls] HTTPS相关知识汇总
    [dpdk][kernel][driver] 如何让DPDK的UIO开机自动加载到正确的网卡上
    [archlinux] linux boot process/order/stage
    [potatos][flex][TBC] 语义分析词法分析 flex
    [daily][tcpdump][bpf] 如何用tcpdump抓到一个分片包
    [daily][dpdk] 网卡offload识别包类型;如何模拟环境构造一个vlan包
    [skill][c] *(char**)
    [apr] Apache Portable Runtime
    [skill] mmap / fwrite / write linux磁盘读写的分层结构
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3097608.html
Copyright © 2020-2023  润新知