• 友元函数


    1 为什么要用友元函数

    结合着类的特性和类中一般成员函数,我们可以这样理解:类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。

    为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员(包括字段和函数)。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

    友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。下面举一例子说明友元函数的应用。

    class Point
    {
    public:
        Point(double xx, double yy) { x=xx; y=yy; }
        void Getxy();
        friend double Distance(Point &a, Point &b);
        friend ostream& operator <<(ostream& out,Point& p);
        friend istream& operator >>(istream& in, Point& p);
        private:
        double x, y;
    };
        void Point::Getxy()
        {
            cout<<x<<" "<<y<<endl;
        }
        double Distance(Point &a, Point &b)
        {
            double dx = a.x - b.x;
            double dy = a.y - b.y;
            a.Getxy();
            return sqrt(dx*dx+dy*dy);
        }
        ostream& operator <<(ostream& out,Point& p){
            out<<p.x<<" "<<p.y;
            return out;
        }
        istream& operator >>(istream& in, Point& p){
            in>>p.x>>p.y;
            return in;
        

    别的类的成员函数作友元,也就是说这2个类相互调用,这样无论谁定义在前在后,编译时都有冲突。要解决这个问题,只要将类的申明、定义、实装分开就可以了。请注意例子中的解说。

    #include <iostream>
    #include <string>
    using namespace std;
    
    class ca;    //事先申明ca类,确保cb类的定义不出错
    
    class cb {    //在ca类之前定义cb类,确保在ca类里申明cb的test()作友元时不出错
    public:
        void test(ca& a);    //由于ca类事先申明,这儿不出错
    };
    
    class ca {
        string id;
        void setId(string s) {
            id = s;
        }
    protected:
        string name;
        void setName(string s) {
            name = s;
        }
    public:
        void print() {
            cout << id << "  " << name << "  " << endl;
        }
        friend void cb::test(ca& a);    //申明cb类的test()函数作友元,允许它访问私有保护成员
    };
    
    void cb::test(ca& a) {  //作友元的成员函数的实装必须在ca类的后面,否则ca类的成员就未定义了。
        a.id = "123";        //这是ca类的私有成员
        a.setName("abc");    //这是ca类的保护成员
    }
    
    int main ( )
    {
        ca a;
        cb b;
        b.test(a);
        a.print();
    
        return 0;
    }

    2 友元类 
          友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。       
          当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
          friend class 类名;
          其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

          例如,以下语句说明类B是类A的友元类:
          class A
          {
                 …
          public:
                 friend class B;
                 …
          };
          经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。

          使用友元类时注意:
                (1) 
    友元关系不能被继承。 
                (2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
                (3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明 

    #include <iostream>  
      
    using namespace std;  
      
    class CObj  
    {  
    public:  
        CObj() : mX(0), mY(0) {}  
        friend class CFriend;  
    private:  
        void PrintData() const  
        {  
            cout << "mX = " << mX << endl  
                 << "mY = " << mY << endl;  
        }  
        int mX;  
        int mY;  
    };  
      
    class CFriend  
    {  
    public:  
        CFriend(int x, int y)  
        {  
            mObj.mX = x;    //直接调用类CObj的私有数据成员  
            mObj.mY = y;  
        }  
        void ShowData() const  
        {  
            mObj.PrintData();   //直接调用类CObj的私有成员函数  
        }  
    private:  
        CObj mObj;  
    };  
      
    int main()  
    {  
        CFriend one(3, 4);  
        one.ShowData();  
        return 0;  
    }
  • 相关阅读:
    Java 学习 第二篇;面向对象 定义类的简单语法:
    Java 学习 第一篇
    Compiler Principles 语法分析
    未来智能机的发展趋势
    C语言IO操作总结
    python学习资料
    JavaScript 数组的创建
    JavaScript中的逗号运算符
    JavaScript本地对象 内置对象 宿主对象
    JavaScript的this用法
  • 原文地址:https://www.cnblogs.com/yxzfscg/p/4769531.html
Copyright © 2020-2023  润新知