• C++友元


    友元是C++提供的一种破坏数据隐蔽和封装的机制

    1.友元函数

    友元函数是在类中使用关键字friend修饰的非成员函数

    1.1友元普通函数

    定义与概念
    • 友元函数是一个普通的函数
    • 友元普通函数在实现时,不需要类名的限定;在调用时,也不需要由实例来调用
    示例代码
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    class Point{
    public:
        Point(int x = 0,int y = 0):x(x),y(y){}
        int getX(){ return x;}//内联函数
        int getY(){ return y;}
        void showData();
        friend float dist(Point &p1,Point &p2);//声明友元函数
    private:
        int x,y;
    };
    
    //普通成员函数的实现,需要类名限定
    void Point::showData(){
        cout << "x: " << x << ", y: " << y << endl;
    }
    
    //因为友元函数是非成员函数,所以不需要类名限制
    float dist(Point &p1,Point &p2){
        double x = p1.x - p2.x;
        double y = p1.y - p2.y;
        return static_cast<float>(sqrt(x*x + y*y));
    }
    
    int main()
    {
        Point p1(1,1),p2(4,5);
        p1.showData();
        p2.showData();
        //调用友元普通函数时,也不需要由类的实例来调用
        cout << "the distance is : " << dist(p1,p2) << endl;
        return 0;
    }
    
    

    1.2友元成员函数

    定义与概念
    • 友元函数是其它类的成员函数
    • 必须先定义包含成员函数的类(比如说A),再在另外一个类(比如说B)中将该成员函数声明为友元函数。此时虽然这个友元函数是A的成员函数,该友元函数仍然称为非成员函数(对于B来说)
    示例代码
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    
    //前向引用声明,否则报错 error: 'Point' does not name a type
    class Point;
    
    class Line{
    public:
        //这时不能使用这样的形式进行初始化:Line(Point p1,Point p2):p1(p1),p2(p2){}
        //因为此时Point的结构尚未定义,error: field 'p1' has incomplete type
        Line(Point p1,Point p2);
        Point& getP1(); //把引用当做函数返回值
        Point& getP2();
        float dist();
    private:
        //不可以这样定义成员变量:Point p1,p2;因为此时Point结构尚不完善
        Point &rp1,&rp2;//类(引用)的组合
    };
    
    class Point{
    public:
        Point(int x = 0,int y = 0):x(x),y(y){}
        int getX(){ return x;}//内联函数
        int getY(){ return y;}
        void showData();
        //声明友元成员函数
        friend float Line::dist();
    private:
        int x,y;
    };
    
    void Point::showData(){
        cout << "x: " << x << ", y: " << y << endl;
    }
    
    //Line类函数的延迟实现开始
    
    //当一个类的成员变量是引用时,需要在初始化列表中初始化引用
    //否则报错:error: uninitialized reference member
    Line::Line(Point p1,Point p2):rp1(p1),rp2(p2){}
    Point& Line::getP1(){
         return rp1;
    }
    Point& Line::getP2(){
         return rp2;
    }
    float Line::dist(){
        double x = rp1.x - rp2.x;
        double y = rp1.y - rp2.y;
        return static_cast<float>(sqrt(x*x + y*y));
    }
    //Line类函数的延迟实现结束
    
    
    int main()
    {
        Point p1(1,1),p2(4,5);
        p1.showData();
        p2.showData();
        Line line(p1,p2);
        cout << "the distance is : " << line.dist() << endl;
        return 0;
    }
    
    

    2.友元类

    定义与概念

    示例代码

    #include <iostream>
    #include <cmath>
    using namespace std;
    
    class Point{
    public:
        Point(int x = 0,int y = 0):x(x),y(y){}
        int getX(){ return x;}//内联函数
        int getY(){ return y;}
        void showData();
        //声明友元类,否则编译不通过,error: 'int Point::x' is private
        friend class Line;
    private:
        int x,y;
    };
    
    void Point::showData(){
        cout << "x: " << x << ", y: " << y << endl;
    }
    
    
    class Line{
    public:
        Line(Point p1,Point p2):p1(p1),p2(p2){}
        Point getP1(){ return p1;}
        Point getP2(){ return p2;}
        float dist();
    private:
        Point p1,p2;//类的组合
    };
    
    float Line::dist(){
        double x = p1.x - p2.x;
        double y = p1.y - p2.y;
        return static_cast<float>(sqrt(x*x + y*y));
    }
    
    int main()
    {
        Point p1(1,1),p2(4,5);
        p1.showData();
        p2.showData();
        Line line(p1,p2);
        cout << "the distance is : " << line.dist() << endl;
        return 0;
    }
    
    

    3.友元的性质

    • 友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元
    • 友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立
    • 友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元

    4.总结

    • 友元是一种破坏数据隐蔽和封装的机制,这是它的用处也是它的坏处。应该尽量避免使用友元
    • 示例代码
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    class Point{
    public:
        Point(int x = 0,int y = 0):x(x),y(y){}
        int getX(){ return x;}//内联函数
        int getY(){ return y;}
        void showData();
        float dist(Point p);
    private:
        int x,y;
    };
    
    void Point::showData(){
        cout << "x: " << x << ", y: " << y << endl;
    }
    
    //通过这样的方式,可以避免使用友元
    float Point::dist(Point p){
        double x = p.x - this->x;
        double y = p.y - this->y;
        return static_cast<float>(sqrt(x*x + y*y));
    }
    
    int main()
    {
        Point p1(1,1),p2(4,5);
        p1.showData();
        p2.showData();
        cout << "the distance is : " << p1.dist(p2) << endl;
        return 0;
    }
    
    

    5.补充

    5.1前向声明

    • 在C++里面可以声明一个类而不定义它。这个声明被称为前向声明(forward declaration)。
    • 在声明之后,定义之前,这个类是一个不完全类型(incompete type),即已知它是一个类型,但不知道包含哪些成员,具有哪些操作。
    • 不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
  • 相关阅读:
    项目管理基本目录结构
    Linux 杀死所有进程
    PHP生成唯一固定长度邀请码
    ubuntu LNMP环境下安装Redis,以及php的redis扩展
    Ubuntu linux 返回上一次访问的目录
    ubuntu删除ppa源
    ubuntu1.8安装lnmp失败
    phpstorm更改sql文件匹配类型
    小程序组件概述
    小程序中WXSS样式控制
  • 原文地址:https://www.cnblogs.com/Libinkai/p/10622473.html
Copyright © 2020-2023  润新知