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

    友元类所有的方法都可以访问原始类的私有成员和保护成员

    声明

    friend class ClassName

    友元声明可以位于公有、私有或保护部分,其所在的位置无关紧要。由于Remote类提到了Tv类,

    所以编译器必须了解Tv类后才能处理Remote类,为些最简单的方法是首先定义Tv类。也可以使用前向声明,稍后介绍

    #include<iostream>
    
    using std::cout;
    using std::cin;
    using std::endl;
    
    class Tv
    {
    private:
        int mode;
        int volume;
    public: 
        friend class Remote;
        Tv(){};
        void Show()
        {
            cout<<"welcome Tv "<<mode<<endl;
        }
        void set_mode(int i){
            mode=i;
            cout<<" mode = "<<mode<<endl;
        };
    
    };
    
    class Remote
    {
    private:
        int mode;
    public:
        void volup(Tv &t,int i)
        {
            t.volume=i;
            cout<<" current volume  "<<t.volume<<endl;
        };
        void ShowTv(Tv &t)
        {
            t.Show();
        }
    };
    
    
    int main()
    {
        Tv _t;
        _t.set_mode(3);
        Remote _r;
        _r.volup(_t,2);
        _r.ShowTv(_t);
        cin.get();
    }

     上边的例子中代码真正访问Tv成员的是Remote方法是volup,其它的方法不是真需要作为友元的。因此它是唯一需要作为友元的方法

    确实可以选择仅让特定的类成员成为另一个类的友元,需不必须让整个类成为友元,但这样稍微有点麻烦,必须小心排列各种声明和定义的顺序。

    让Remote::volup()成为Tv类的友元的方法,在Tv类声明中将其声明为友元

    class

    {

      friend void Remote::set_chan(Tv & t,int c);

    };

     然而,要使编译器能够处理这条语句,它必须知道Remote的定义,否则就无法知道Remote是一个类,而set_chan是这个类的方法。

    这意味着就将Remote的定义放到Tv的定义前面。Remote的方法提到了Tv对象,而这意味着Tv定义应当位于Remote定义之前。避开这种循环

    依赖的方法是,使用前向声明(forward declaration)为此,需要在Remote定义的前面插入下面的语句:

    class Tv

    这样排列次序应如下:

    class Tv;

    class Remote{...};

    class Tv {....};

     还有一个麻烦。程序清单Remote声明包含了内联代码,例如:

    void volup(Tv &t,int i)
    {
    t.volume=i;
    cout<<" current volume "<<t.volume<<endl;
    };

    由于这将调用Tv的一个方法,所以编译器此时必须已经看到了Tv类的声明,这样才能知道Tv有哪些方法,但正如看到的,该声明位于Remote声明方法后

    。这种问题的解决方法是,使用Remote声明中只包含方法声明,并将实际的定义放在Tv类之后。这样

    Remote方法的原型与下面类似:

    void volup(Tv &t,int i);

    检查该原型时,所有的编译器都需要知道Tv是一个类,而前向声明提供了这样的信息。当编译器到达真正的方法定义时,它已经读取了Tv类的声明,

    并拥有了编译这些方法所需的信息。能过在方法定义中使用inline关键字,仍然可以使其成为内联方法。

    #include<iostream>
    
    using std::cout;
    using std::cin;
    using std::endl;
    
    class Tv;
    
    class Remote
    {
    private:
        int mode;
    public:
        void volup(Tv &t,int i);
        void ShowTv(Tv &t);
    };
    
    class Tv
    {
    private:
        int mode;
        int volume;
    public: 
        friend void Remote::volup(Tv & t,int c);
        Tv(){};
        void Show()
        {
            cout<<"welcome Tv "<<mode<<endl;
        }
        void set_mode(int i){
            mode=i;
            cout<<" mode = "<<mode<<endl;
        };
    
    };
    
    inline void Remote::volup(Tv & t,int i)
    {
        t.volume=i;
        cout<<" current volume  "<<t.volume<<endl;
    };
    
    inline void Remote::ShowTv(Tv & t)
    {
        t.Show();
    };
    
    int main()
    {
        Tv _t;
        _t.set_mode(3);
        Remote _r;
        _r.volup(_t,2);
        _r.ShowTv(_t);
        cin.get();
    }

    内联函数的链接性是内部的,这意味着函数定义必须在使用函数的文件中,这个例子中内联定义位于头文件中,因此在使用函数的文件中包含

    头文件可确保将定义放在正确的地方。这可以将定义放在实现文件中,但必须删除关键字inline这样函数的链接性将是外部的

     再看一个操作符重载的小例子

    #include<iostream>
       
    
    class B
    {
    public :
        B()
        {
            myValue=2;
            std::cout<<"B init"<<std::endl;
        }
        ~B()
        {
            std::cout<<"B end"<<std::endl;
        }
        
        //这样做可以
        /*B operator+(const B av)
        {
            B a;
            a.myValue=myValue+av.myValue;
            return a;
        }*/
        //也可以这么做
        friend B operator+(const B b1,const B b2);
    
        //------------------------------------------------
        int GetMyValue()
        {
            return myValue;
        }
        //重载<<
        friend std::ostream& operator<<(std::ostream& os,B);
    private :
        int myValue;
    };
    
    B operator+(const B b1,const B b2)
    {
        B a;
        a.myValue=b1.myValue+b2.myValue;
        return a;
    }
    std::ostream& operator<<(std::ostream& os,B b)
    {
        return os<<"重载实现:"<<b.myValue<<std::endl;
    }
    int main()
    {
        B b1;
        std::cout<<b1;
        B b2;
        B b3=b1+b2;
        std::cout<<b3<<std::endl;
        std::cin.get();
        return 0;
    }
  • 相关阅读:
    golang学习笔记(7)--函数式编程
    golang学习笔记(6)--面向接口编程
    go语言学习笔记(5)--面向对象
    go语言学习笔记(4)--容器与字符串的基本概念
    go语言学习笔记(3)--简单的程序设计
    go语言学习笔记(2)--go语言语法细节与基本数据类型
    go语言学习笔记(1)--第一个go语言程序
    Linux学习笔记系列(1)
    Scrapy爬虫小demo总结
    python基础总结(6)
  • 原文地址:https://www.cnblogs.com/li-peng/p/3514543.html
Copyright © 2011-2022 走看看