• 友元


    • 友元是一种允许非类成员函数访问类的非公有成员的一种机制。
    • 可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元。
    1. 友元函数
    2. 友元类

    •  友元函数在类作用域外定义,但它需要在类体中进行说明
    • 为了与该类的成员函数加以区别,定义的方式是在类中用关键字friend说明该函数,格式如下:
      friend  类型 友元函数名(参数表);
    • 友元的作用在于提高程序的运行效率。

    下面用程序来使用下友元:

    #include <iostream>
    using namespace std;
    
    class Point {
        friend double distance(const Point& p1, const Point& p2);//声明友员函数
    public:
        Point(int x, int y);
    private:
        int x_;
        int y_;
    };
    
    Point::Point(int x, int y):x_(x), y_(y) {
    
    }
    
    int main(void) {
        return 0;
    }

    其中友员函数并不是类的成员函数,为了证明这点,我们先假设友员是成员函数,所以可以这样写:

    编译一下:

    友员的定义是在类体之外的,所以正确的实现友员函数的写法是去掉域访问修饰,如下:

    既始在定义友元函数时在类体中实现实际上它也是在类体外:

    下面来具体实现它,求两点之间的距离:

    编译:

    可见友元确实是可以访问类的私有变量,下面编写一下测试代码:

    编译:

    呃,这是啥子错,纠结了关天,最终发现是函数名的问题,可能是distance与系统函数重名了,所以需要修改一下,将首字母改为大写就OK了:

    运行:

    这就是友元使用的效果,在上面中说到“友元的作用在于提高程序的运行效率。”,何以见得呢?如果这个程序不用友元的话,则需要提供两个访问私有成员的函数,多了函数调用的开销。

    • 友元函数不是类的成员函数,在函数体中访问对象的成员,必须用对象名加运算符“.”加对象成员名。但友元函数可以访问类中的所有成员(公有的、私有的、保护的),一般函数只能访问类中的公有成员。
    • 友元函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护部分,但结果一样。
    • 某类的友元函数的作用域并非该类作用域。如果该友元函数是另一类的成员函数,则其作用域为另一类的作用域,否则与一般函数相同。
    • 友元函数破坏了面向对象程序设计类的封装性,所以友元函数如不是必须使用,则尽可能少用。或者用其他手段保证封装性。

    • 如果某类B的成员函数会频繁的存取另一个类A的数据成员, 而A的数据成员的Private/Protectd限制造成B存取的麻烦, B只能通过A的Public的成员函数进行间接存取。
    • 把B做成A类的友元类,即A类向B类开发其Private/Protectd内容, 让B直接存取。
    • 友元类:一个类可以作另一个类的友元。
    • 友元类的所有成员函数都是另一个类的友元函数。
    • 友元类的声名:
      friend class 类名;

     下面来编写一个摇控器控制电视机的例子来说明友元类的使用:

    #include <iostream>
    using namespace std;
    
    //电视机
    class Television {
    public:
        Television(int volume, int chanel):volume_(volume),chanel_(chanel) {
    
        }
    private:
        int volume_;//音量
        int chanel_;//频道
    };
    
    //摇控器
    class TeleController {
    public:
        void volumeUp(Television& tv) {
            tv.volume_ += 1;
        }
    
        void volumeDown(Television& tv) {
            tv.volume_ -= 1;
        }
    
        void chanelUp(Television& tv) {
            tv.chanel_ += 1;
        }
    
        void chanelDown(Television& tv) {
            tv.chanel_ -= 1;
        }
    };
    
    int main(void) {
        return 0;
    }

    编译:

    那友元类派上用场了:

    #include <iostream>
    using namespace std;
    
    //电视机
    class Television {
        friend class TeleController;//将摇控器类声明为电视机的友员类,这样它的私有成员对于摇控器而言就全公开了
    public:
        Television(int volume, int chanel):volume_(volume),chanel_(chanel) {
    
        }
    private:
        int volume_;//音量
        int chanel_;//频道
    };
    
    //摇控器
    class TeleController {
    public:
        void volumeUp(Television& tv) {
            tv.volume_ += 1;
        }
    
        void volumeDown(Television& tv) {
            tv.volume_ -= 1;
        }
    
        void chanelUp(Television& tv) {
            tv.chanel_ += 1;
        }
    
        void chanelDown(Television& tv) {
            tv.chanel_ -= 1;
        }
    };
    
    int main(void) {
        return 0;
    }

    再次编译:

    这时编写测试代码:

    这里就不打印了,重在说明友元类的使用,电视机与遥控器类是写在一个cpp文件中,如果单独写在不同的cpp文件中会怎么呢?下面来看下:

     

    Television.h:

    #ifndef _TELEVISION_H_
    #define _TELEVISION_H_
    
    class Television
    {
        friend class TeleController;
    public:
        Television(int volume, int chanel);
    private:
        int volume_;
        int chanel_;
    };
    
    #endif // _TELEVISION_H_

    Television.cpp:

    #include "Television.h"
    
    Television::Television(int volume, int chanel) : volume_(volume), chanel_(chanel)
    {
    
    }

    TeleController.h:

    #ifndef  _TELE_CONTROLLER_H_
    #define _TELE_CONTROLLER_H_
    
    class TeleController
    {
    public:
        void VolumeUp(Television& tv);
    
        void VolumeDown(Television& tv);
    
        void ChanelUp(Television& tv);
    
        void ChanelDown(Television& tv);
    };
    
    #endif // _TELE_CONTROLLER_H_

    TeleController.cpp:

    #include "TeleController.h"
    
    void TeleController::VolumeUp(Television& tv)
    {
        tv.volume_ += 1;
    }
    
    void TeleController::VolumeDown(Television& tv)
    {
        tv.volume_ -= 1;
    }
    
    void TeleController::ChanelUp(Television& tv)
    {
        tv.chanel_ += 1;
    }
    
    void TeleController::ChanelDown(Television& tv)
    {
        tv.volume_ -= 1;
    }

    02.cpp:

    #include <iostream>
    using namespace std;
    
    int main(void) {
        return 0;
    }

    这时编译:

    报错了,说明Television对于TeleController类在这种情况下是不可见的:

    再次编译:

    实际上遥控器头文件中的电视机引用也可以用前向声明来搞,修改代码如下:

    再在具体实现中包含头文件既可:

    修改之后再编译,依然好使,那这种前向声明它是有好外的:TeleController.h头文件会相对而言小一些,如果直接包含Television.h头文件,如果在多个文件中包含TeleController.h文件则文件会增大。

    • 友元关系是单向的
      A是B的友元类(在B类中有friend class A),并不代表B也是A的友元类。
    • 友元关系不能被传递
      A是B的友元类,B又是C的友元类,并不代表A是C的友元类。
    • 友元关系不能被继承
      A是B的友元类,C继承A,并不代表C是B的友元类。
  • 相关阅读:
    Linux: 安装和启用firefox浏览器的java
    Latex: beamer
    时频分析:窗口傅立叶变换
    Python: 面向对象
    Linux: 安装NVIDIA显卡驱动
    Matlab: 路径的操作
    python--文件读写
    python--函数
    python--数据类型
    网络基础——网络协议
  • 原文地址:https://www.cnblogs.com/webor2006/p/5247394.html
Copyright © 2020-2023  润新知