zoukankan      html  css  js  c++  java
  • C++ 友元

    友元

    友元 英文 friendfriend 翻译成中文就是朋友,翻译成术语就是:友元。朋友就很好理解了,我的钱你随便花,我的东西你随便用;当然我也是你的朋友,你的钱我随便花,你的东西我随便用。

    当然在 C++ 里,类与类 之间可以作为友元,那么这个类就可以去操作另外一个类里面私有的成员;函数与函数 之间也可以作为 友元,所以友元分为: 友元函数友元类

    我们通过一个例子一看就明白了:

    写代码

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Screen{
    public:
        typedef std::string::size_type index;
    
        Screen(int ht=0, int wd=0):contents(ht*wd, ' '), cursor(0), height(ht), width(wd){}
    
        int area() const{
            return height * width;
        }
    private:
        std::string contents; 
        index cursor;
        int height, width;
    };
    
    
    
    int main(){
        Screen a;
        cout << a.area() << endl;
        cout << "OK" << endl;
    
        return 0;
    }

    运行现在的程序,程序是可以正常使用的。

    现在,我们在main() 函数的同一级,编写一个函数,这个函数的功能是:计算屏幕(Screen)的面积。

    // 这个函数不是类的成员函数
    int calcArea(Screen & screen){
        return screen.height * screen.width;
    }

    如果这个函数像上面这个样子编写,程序编译都通不过。因为 heightwidth 都是 Screen 类的私有成员。这两个私有的数据成员只能在类的内部使用,只能被类的内部函数使用,因为这个calcArea() 函数不是类内部的成员函数,所以它是不能使用类内部的私有成员的。
    那么,假如现在,我们把这个 calcArea() 函数变成这个 Screen 类的友元,就是朋友,那么这个函数就可以使用类里面私有的成员了。就像是:你是我的朋友,到我家里来,就像到自己家里一样,随便吃随便用随便拿。

    现在我们就来定义友元函数。我们将calcArea() 函数定义成友元函数。

    Screen 类里面,public里面添加下面这句代码就可以。就这么简单:

        friend int calcArea(Screen & screen);

    现在,我们在编译程序,就没有错误了。运行也没有问题。main() 函数里面写成下面这个样子,来测试:

    int main(){
        Screen a;
        cout << a.area() << endl;
        cout << calcArea(a) << endl;
        cout << "OK" << endl;
        while(1){}
        return 0;
    }

    我们也可以将一个类编写成友元,我们现在来看下面这个例子:(注意: 要将下面的这段代码放到Screen类的下面,否则Window_Mgr类找不到 Screen类。)

    // 窗口管理类 - 对Screen类进行管理
    class Window_Mgr{
    public:
        // 重定位 - 就是改变窗口的height 和 width
        void relocate(int r, int c, Screen& s){
            s.height += r;
            s.width + c;
        }
    };

    因为 Screen 类里的 heightwidth 是私有的,不能再 Window_Mgr 类里面使用的,除非它是友元。
    现在编译程序是报错的。
    我们现在可以将Window_Mgr类作为Screen类的友元。需要做的事情,只需要:在Screen类里面的public里面添加下面一句代码:

        friend class Window_Mgr;

    现在,我们将Window_Mgr 这个整个类都作为 Screen类的友元,也就是说:它们现在是朋友,我们家里的人可以随便到你们家里面来,你们家里的人也可以随便到我们家里面来。

    我们在 main() 函数里面测试一下:

    int main(){
        Screen a(60, 100);
        cout << a.area() << endl;
    
        Window_Mgr w;
        w.relocate(10, 20, a);
        cout << calcArea(a) << endl;
    
        cout << "OK" << endl;
        while(1){}
        return 0;
    }

    这就是友元,懂了吗?


    如果我们现在不行让这个 Window_Mgr类作为 Screen类的友元,而是希望只是 Window_Mgr类中的一个成员函数是Screen类的友元。要如何操作呢?

    我们在定义一个类,DogDog类里面就有很多的成员函数。

    我现在不想将Dog类全部做成Screen类的友元,我只想将Dog类里面的foo()共有函数作为Screen类的友元,那现在我们要如何去做呢?
    很简单,我们在Screen类的public里面添加下面这句代码就可以:

        friend int Dog::foo(Screen & );

    Q: 现在程序编译时会通过的,这是为什么?


    A: 有一个问题需要强调一下:友元定义 和 友元声明 之间有一个依赖。

    如果我们将 Dog 类 放在 Screen 类的下面,那么 Dog 类是可以找到 Screen 类,但是 Screen 类却找不到 Dog 类里面的foo() 函数,因为我们在编写 foo() 函数的时候,是使用的声明和定义一体的形式编写的。
    如果我们将 Dog 类 放在 Screen 类的上面, 那么 Screen 类是可以找到 Dog 类里面的 foo() 函数,但是 Dog 类现在又找不到 Screen 类了。所以,不管你将 Dog 类放在程序的什么位置,程序都是没有办法编译通过。要怎样解决这个问题呢?

    我们需要在 Screen 类上面 这样写:

    class Screen;
    
    class Dog{
    public:
        int foo(Screen & screen);
    
        int koo(Screen & screen){
            return 1;
        }
    };
    

    先对 Screen 类进行声明,接下定义 Dog 类。并且在 Dog 类里面 我们将 foo() 函数写成声明的形式。这样就没有使用到 Screen 类里面的成员,这样,程序在编译这段代码的时候不需要去找 Screen 的定义。


    接着,我们在 Screen 类的下面 这样写:

    int Dog::foo(Screen & screen){
        return  screen.height * screen.width;
    }

    我们在 Screen 类的下面都 Dog 类里面的成员函数 foo() 函数进行定义。这样做的原因是:因为 foo() 成员函数里面使用到了 Screen 类里面定义的成员变量,程序在编译这段函数的代码的时候,会去上向上找 Screen 类的定义,刚好我们将 foo() 函数的定义写在Screen 定义的下面,所以这样写就可以用个编译。

    现在在main() 函数中写一些测试代码:

    int main(){
        Screen a(60, 100);
        cout << a.area() << endl;
    
        Dog d;
        cout << d.foo(a) << endl;
    
        cout << "OK" << endl;
        while(1){}
        return 0;
    }

    现在 友元 我们就都介绍完毕了。

    最后,完整的代码贴上:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Screen;
    
    class Dog{
    public:
        int foo(Screen & screen);
    
        int koo(Screen & screen){
            return 1;
        }
    };
    
    
    class Screen{
    public:
        friend int calcArea(Screen & screen);
        friend class Window_Mgr;
        friend int Dog::foo(Screen & screen);
    
        typedef std::string::size_type index;
    
        Screen(int ht=0, int wd=0):contents(ht*wd, ' '), 
            cursor(0), height(ht), width(wd){}
    
        int area() const{
            return height * width;
        }
    
    private:
        std::string contents; 
        index cursor;
        int height, width;
    };
    
    // 窗口管理类 - 对Screen类进行管理
    class Window_Mgr{
    public:
        // 重定位 - 就是改变窗口的height 和 width
        void relocate(int r, int c, Screen& s){
            s.height += r;
            s.width += c;
        }
    };
    
    int Dog::foo(Screen & screen){
        return  screen.height * screen.width;
    }
    
    
    // 这个函数不是类的成员函数
    int calcArea(Screen & screen){
        return screen.height * screen.width;
    }
    
    int main(){
        Screen a(60, 100);
        cout << a.area() << endl;
    
        Window_Mgr w;
        w.relocate(10, 20, a);
        cout << calcArea(a) << endl;
    
        Dog d;
        cout << d.foo(a) << endl;
    
        cout << "OK" << endl;
        while(1){}
        return 0;
    }
    


    总结:
    1 . 今天我们学习的就是友元,友元就是找朋友。我们可以将一个函数作为友元,我们也可以将一个类作为友元,也可以将类中的一个成员函数作为友元。
    2 . 所有友元函数有两种: 普通函数 和 类的成员函数(共有 和 私有都可以。)
    3 . 友元,道理上是很简单的。友元了之后,就可以操作所有私有的数据成员和私有函数。

  • 相关阅读:
    Linux Shell tr 命令详解
    Shell统计每个单词出现的个数
    启明4-29团队进度博客
    启明4-28团队进度博客
    启明4-27团队进度博客
    启明4-26团队进度博客
    启明4-25团队进度博客
    启明4-24团队博客
    每日总结8
    启明4-23团队进度博客
  • 原文地址:https://www.cnblogs.com/aobosir/p/5928535.html
Copyright © 2011-2022 走看看