zoukankan      html  css  js  c++  java
  • 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),即已知它是一个类型,但不知道包含哪些成员,具有哪些操作。
    • 不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
  • 相关阅读:
    pat甲级 1155 Heap Paths (30 分)
    pat甲级 1152 Google Recruitment (20 分)
    蓝桥杯 基础练习 特殊回文数
    蓝桥杯 基础练习 十进制转十六进制
    蓝桥杯 基础练习 十六进制转十进制
    蓝桥杯 基础练习 十六进制转八进制
    51nod 1347 旋转字符串
    蓝桥杯 入门训练 圆的面积
    蓝桥杯 入门训练 Fibonacci数列
    链表相关
  • 原文地址:https://www.cnblogs.com/Libinkai/p/10622473.html
Copyright © 2011-2022 走看看