友元函数 订阅
友元函数是指某些虽然不是类成员却能够访问类的所有成员的函数。类授予它的友元特别的访问权。通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。 展开全文
友元函数是指某些虽然不是类成员却能够访问类的所有成员的函数。类授予它的友元特别的访问权。通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。
信息
外文名
friend
类    型
虚拟函数
中文名
友元函数
学    科
计算机科学
友元函数友元函数
成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38),就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。关于这一点就这么简单。如果函数不必是虚拟的,情况就稍微复杂一点。()看下面表示有理数的一个类:class rational {public:rational(int numerator = 0,int denominator = 1);int numerator() const;int denominator() const;private:...};这是一个没有一点用处的类。(用条款18的术语来说,接口的确最小,但远不够完整。)所以,要对它增加加,减,乘等算术操作支持,但是,该用成员函数还是非成员函数,或者,非成员的友元函数来实现呢?当拿不定主意的时候,用面向对象的方法来考虑!有理数的乘法是和rational类相联系的,所以,写一个成员函数把这个操作包到类中。class rational {public:...const rational operator*(const rational& rhs) const;};(如果你不明白为什么这个函数以这种方式声明——返回一个const值而取一个const的引用作为它的参数——参考条款21-23。)条款21: 尽可能使用const条款22: 尽量用“传引用”而不用“传值”条款23: 必须返回一个对象时不要试图返回一个引用可以很容易地对有理数进行乘法操作:rational oneeighth(1,8);rational onehalf(1,2);rational result = onehalf * oneeighth; // 运行良好result = result * oneeighth; // 运行良好但不要满足,还要支持混合类型操作,比如,rational要能和int相乘。但当写下下面的代码时,只有一半工作:result = onehalf * 2; // 运行良好result = 2 * onehalf; // 出错!这是一个不好的苗头。记得吗?乘法要满足交换律。如果用下面的等价函数形式重写上面的两个例子,问题的原因就很明显了:result = onehalf.operator*⑵; // 运行良好result = 2.operator*(onehalf); // 出错!对象onehalf是一个包含operator*函数的类的实例,所以编译器调用了那个函数。而整数2没有相应的类,所以没有operator*成员函数。编译器还会去搜索一个可以象下面这样调用的非成员的operator*函数(即,在某个可见的名字空间里的operator*函数或全局的operator*函数):result = operator*(2,onehalf); // 错误!但没有这样一个参数为int和rational的非成员operator*函数,所以搜索失败。再看看那个成功的调用。它的第二参数是整数2,然而rational::operator*期望的参数却是rational对象。怎么回事?为什么2在一个地方可以工作而另一个地方不行?秘密在于隐式类型转换。编译器知道传的值是int而函数需要的是rational,但它也同时知道调用rational的构造函数将int转换成一个合适的rational,所以才有上面成功的调用(见条款m19)。换句话说,编译器处理这个调用时的情形类似下面这样:const rational temp⑵; // 从2产生一个临时// rational对象result = onehalf * temp; // 同onehalf.operator*(temp);当然,只有所涉及的构造函数没有声明为explicit的情况下才会这样,因为explicit构造函数不能用于隐式转换,这正是explicit的含义。如果rational象下面这样定义:class rational {public:explicit rational(int numerator = 0,// 此构造函数为int denominator = 1); // explicit...const rational operator*(const rational& rhs) const;...};那么,下面的语句都不能通过编译:result = onehalf * 2; // 错误!result = 2 * onehalf; // 错误!这不会为混合运算提供支持,但至少两条语句的行为一致了。然而,我们刚才研究的这个类是要设计成可以允许固定类型到rational的隐式转换的——这就是为什么rational的构造函数没有声明为explicit的原因。这样,编译器将执行必要的隐式转换使上面result的第一个赋值语句通过编译。实际上,如果需要的话,编译器会对每个函数的每个参数执行这种隐式类型转换。但它只对函数参数表中列出的参数进行转换,决不会对成员函数所在的对象(即,成员函数中的*this指针所对应的对象)进行转换。这就是为什么这个语句可以工作:result = onehalf.operator*⑵; // converts int -> rational而这个语句不行:result = 2.operator*(onehalf); // 不会转换// int -> rational第一种情形操作的是列在函数声明中的一个参数,而第二种情形不是。尽管如此,你可能还是想支持混合型的算术操作,而实现的方法应该清楚了:使operator*成为一个非成员函数,从而允许编译器对所有的参数执行隐式类型转换:class rational {... // contains no operator*};// 在全局或某一名字空间声明,// 参见条款m20了解为什么要这么做const rational operator*(const rational& lhs,const rational& rhs){return rational(lhs.numerator() * rhs.numerator(),lhs.denominator() * rhs.denominator());}rational onefourth(1,4);rational result;result = onefourth * 2; // 工作良好result = 2 * onefourth; // 万岁,它也工作了!这当然是一个完美的结局,但还有一个担心:operator*应该成为rational类的友元吗?这种情况下,答案是不必要。因为operator*可以完全通过类的公有(public)接口来实现。上面的代码就是这么做的。只要能避免使用友元函数就要避免,因为,和现实生活中差不多,友元(朋友)带来的麻烦往往比它(他/她)对你的帮助多。然而,很多情况下,不是成员的函数从概念上说也可能是类接口的一部分,它们需要访问类的非公有成员的情况也不少。让我们回头再来看看本书那个主要的例子,string类。如果想重载operator>>;和operator<<;来读写string对象,你会很快发现它们不能是成员函数。如果是成员函数的话,调用它们时就必须把string对象放在它们的左边:// 一个不正确地将operator>>;和// operator<<;作为成员函数的类class string {public:string(const char *value);...istream& operator>>(istream& input);ostream& operator<<(ostream& output);private:char *data;};string s;s >> cin; // 合法,但// 有违常规s << cout; // 同上这会把别人弄糊涂。所以这些函数不能是成员函数。注意这种情况和前面的不同。这里的目标是自然的调用语法,前面关心的是隐式类型转换。istream& operator>>(istream& input,string& string){delete [] string.data;read from input into some memory,and make string.datapoint to itreturn input;}ostream& operator<<(ostream& output,const string& string){return output << string.data;}注意上面两个函数都要访问string类的data成员,而这个成员是私有(private)的。但我们已经知道,这个函数一定要是非成员函数。这样,就别无选择了:需要访问非公有成员的非成员函数只能是类的友元函数。假设f是想正确声明的函数,c是和它相关的类:·虚函数必须是成员函数。如果f必须是虚函数,就让它成为c的成员函数。·operator>>;和operator<<;决不能是成员函数。如果f是operator>>;或operator<<;,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。·只有非成员函数对最左边的参数进行类型转换。如果f需要对最左边的参数进行类型转换,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。·其它情况下都声明为成员函数。如果以上情况都不是,让f成为c的成员函数。
收起全文
精华内容
下载资源
问答
  • 现在先说说赋值运算符“=”的重载C++规定赋值运算符“=”只能重载为类的非静态成员函数,而不可以重载为类的友元函数。不能重载为类的静态成员应该比较容易理解,因为静态成员函数是属于整个类的,不是属于某个对象...
  • 以下是对C++运算符重载 成员函数与友元函数进行了介绍,需要的朋友可以过来参考下
  • 关于c+模板之友元类友元函数的实例化,图形界面之矩形。
  • 友元函数的好例子

    2015-03-06 16:39:56
    友元函数的好例子 lass X { private: int i; public: X(int ii) { i=ii; } int getX() { return i; } friend int g(X x
  • 写的很好的c++PPT
  • 一个实例,实现运算符重载(成员函数和非成员函数两种方式),友元函数的使用,注意事项等,自己学习时编写的,
  • 友元函数

    2020-10-07 21:14:02
    友元函数 友元函数的作用:提供直接访问对象的私有成员的接口。通过友元,一个不同函数或另一个类中的成员函数可以访问类中的私有成员和保护成员。 友元函数可以访问对象的私有成员,保护成员,但是普通函数不行 ...

    友元函数

    友元函数的作用:提供直接访问对象的私有成员的接口。通过友元,一个不同函数或另一个类中的成员函数可以访问类中的私有成员和保护成员。

    1. 友元函数可以访问对象的私有成员,保护成员,但是普通函数不行

    2. 友元函数不能直接访问类的成员,只能访问对象成员,因此在写友元函数之前,先确定一个对象。

      2.1.传参的对象
      2.2.在函数中创建对象
      

    注意点:并不是赋予函数具有访问私有或者保护属性的数据
    在友元函数中赋予对象具有这样的权利

    #include<iostream>
    #include<string>
    using namespace std;
    class Student
    {
    public:
    	MM(string name,int age):name(name),age(age){}
    	void print()
    	{
    		cout<<name<<"\t"<<age <<endl;
    	}
    	//需要在函数中创建对象
    	friend void printInfo();
    protected:
    	string name;
    	int age;
    }
    
    class Student
    {
    public:
    	MM(string name,int age):name(name),age(age){}
    	void print()
    	{
    		cout<<name<<"\t"<<age <<endl;
    	}
    	//传入对象
    	friend void printInfo1(MM object);
    protected:
    	string name;
    	int age;
    }
    
    //方法一的函数
    void printInfo()
    {
    	Student mm("张三",19);
    	cout<<mm.name<<"\t"<<mm.age<<endl;
    }
    
    //方法二的函数
    void printInfo1(Student object)
    {
    	cout<<object.name<<"\t"<<object.age<<endl;
    }
    
    int main()
    {
    	Student("李四",18);
    	printInfo();
    	printInfo1(mm);
    }
    

    总结:友元函数就是赋予对象具有打破权限限定,但打破权限又必须在友元函数内访问。

    展开全文
  • 二、友元函数友元函数在类作用域外定义,但它需要在类体中进行说明为了与该类的成员函数加以区别,定义的方式是在类中用关键字friend说明该函数,格式如下: friend 类型 友元函数名(参数表);友元的作用在于提高...
  • 友元函数代码实例

    2015-05-19 19:56:54
    友元函数,类外普通函数声明为类的友元,之后即可与类共享数据
  • C++——友元函数&内联函数

    千次阅读 多人点赞 2018-12-07 23:55:15
    友元函数 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。 友元可以是一个函数,该函数被...

    友元函数

    类的友元函数是定义在类外部但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数

    友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

    如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:

    class Box
    {
       double width;
    public:
       double length;
       friend void printWidth( Box box );
       void setWidth( double wid );
    };
    #include <iostream>
     
    using namespace std;
     
    class Box
    {
       double width;
    public:
       friend void printWidth( Box box );
       void setWidth( double wid );
    };
    
    // 成员函数定义
    void Box::setWidth( double wid )
    {
        width = wid;
    }
    
    // printWidth() 不是任何类的成员函数
    void printWidth( Box box )
    {
       /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
       cout << "Width of box : " << box.width <<endl;
    }
     
    // 程序的主函数
    int main( )
    {
       Box box;
     
       // 使用成员函数设置宽度
       box.setWidth(10.0);
       
       // 使用友元函数输出宽度
       printWidth( box );
     
       return 0;
    }
    /*输出结果是
    Width of box : 10
    */

    内联函数

    内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

    对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

    如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。

    在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。

     

    #include <iostream>
     
    using namespace std;
    
    inline int Max(int x, int y)
    {
       return (x > y)? x : y;
    }
    
    // 程序的主函数
    int main( )
    {
    
       cout << "Max (20,10): " << Max(20,10) << endl;
       cout << "Max (0,200): " << Max(0,200) << endl;
       cout << "Max (100,1010): " << Max(100,1010) << endl;
       return 0;
    }

    以下内容转载自:https://blog.csdn.net/u011327981/article/details/50601800/

    1.  内联函数

    在C++中我们通常定义以下函数来求两个整数的最大值:

    复制代码 代码如下:


    int max(int a, int b)
    {
     return a > b ? a : b;
    }

    为这么一个小的操作定义一个函数的好处有:

    ① 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它的含义要容易得多

    ② 如果需要做任何修改,修改函数要比找出并修改每一处等价表达式容易得多

    ③ 使用函数可以确保统一的行为,每个测试都保证以相同的方式实现

    ④ 函数可以重用,不必为其他应用程序重写代码

    虽然有这么多好处,但是写成函数有一个潜在的缺点:调用函数比求解等价表达式要慢得多。在大多数的机器上,调用函数都要做很多工作:调用前要先保存寄存器,并在返回时恢复,复制实参,程序还必须转向一个新位置执行

    C++中支持内联函数,其目的是为了提高函数的执行效率,用关键字 inline 放在函数定义(注意是定义而非声明,下文继续讲到)的前面即可将函数指定为内联函数,内联函数通常就是将它在程序中的每个调用点上“内联地”展开,假设我们将 max 定义为内联函数:

    复制代码 代码如下:


    inline int max(int a, int b)
    {
     return a > b ? a : b;
    }

    则调用: cout<<max(a, b)<<endl;


    在编译时展开为: cout<<(a > b ? a : b)<<endl;

    从而消除了把 max写成函数的额外执行开销

    2.  内联函数和宏

    无论是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” 条款,还是《高质量程序设计指南——C++/C语言》中的“用函数内联取代宏”,宏在C++中基本是被废了,在书《高质量程序设计指南——C++/C语言》中这样解释到:

    3.  将内联函数放入头文件

    关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

    如下风格的函数 Foo 不能成为内联函数:

    复制代码 代码如下:


    inline void Foo(int x, int y);   // inline 仅与函数声明放在一起   
    void Foo(int x, int y)
    {
     ...

    而如下风格的函数 Foo 则成为内联函数:

    复制代码 代码如下:


    void Foo(int x, int y);   
    inline void Foo(int x, int y)   // inline 与函数定义体放在一起
    {
     ...

    所以说,C++ inline函数是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了 inline 关键字,但我认为 inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

    定义在类声明之中的成员函数将自动地成为内联函数,例如:

    复制代码 代码如下:


    class A
    {  
    public:
     void Foo(int x, int y) { ... }   // 自动地成为内联函数  

    但是编译器是否将它真正内联则要看 Foo函数如何定义

    内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。

    当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。

    但是你会很奇怪,重复定义那么多次,不会产生链接错误?

    我们来看一个例子:

    A.h :

    复制代码 代码如下:


    class A
    {
    public:
     A(int a, int b) : a(a),b(b){}
     int max();

    private:
     int a;
     int b;
    };

    A.cpp : 

    复制代码 代码如下:


    #include "A.h"

    inline int A::max()
    {
     return a > b ? a : b;
    }

    Main.cpp : 

    复制代码 代码如下:


    #include <iostream>
    #include "A.h"
    using namespace std;

    inline int A::max()
    {
     return a > b ? a : b;
    }

    int main()
    {
     A a(3, 5);
     cout<<a.max()<<endl;
     return 0;
    }

    一切正常编译,输出结果:5

     


    倘若你在Main.cpp中没有定义max内联函数,那么会出现链接错误:

    error LNK2001: unresolved external symbol "public: int __thiscall A::max(void)" (?max@A@@QAEHXZ)main.obj
    找不到函数的定义,所以内联函数可以在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的就可以。

    在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。

    4.  慎用内联

    内联虽有它的好处,但是也要慎用,以下摘自《高质量程序设计指南——C++/C语言》:

    而在Google C++编码规范中则规定得更加明确和详细:

    内联函数:

    Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数.

    定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
    优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
    缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
    结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!
    另一个实用的经验准则: 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行).
    有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.

    -inl.h文件:


    Tip: 复杂的内联函数的定义, 应放在后缀名为 -inl.h 的头文件中.


    内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 然而, 实现代码理论上应该放在 .cc 文件中, 我们不希望 .h 文件中有太多实现代码, 除非在可读性和性能上有明显优势.

    如果内联函数的定义比较短小, 逻辑比较简单, 实现代码放在 .h 文件里没有任何问题. 比如, 存取函数的实现理所当然都应该放在类定义内. 出于编写者和调用者的方便, 较复杂的内联函数也可以放到 .h 文件中, 如果你觉得这样会使头文件显得笨重, 也可以把它萃取到单独的 -inl.h 中. 这样把实现和类定义分离开来, 当需要时包含对应的 -inl.h 即可。

     

    部分资料来源于菜鸟教程

    展开全文
  • 以下是对C++中的友元函数进行了详细的总结介绍,需要的朋友可以过来参考下
  • xxx xxxxx 目 录 页 xx C++语言程序设计 xxx xxxxx 目 录 页 C++语言程序设计 绪 论 大连理工大学出版社 地址大连市软件园路80号 E-mail : dutp@ URLhttp://www.dutp,cn 友元函数和友元类 友元函数和友元类 类具有...
  • 当声明了友元函数或者友元类之后,该函数或者类可以访问类的所有成员,包括private成员,当然访问过程需要通过类的对象进行。例如声明一个友元函数,有两种情况: ①该函数是普通的全局函数 一般情况下,使用一个...

    友元声明

    前面加上关键字friend,该声明可以放在任何一个地方,一般放在类的定义中。当声明了友元函数或者友元类之后,该函数或者类可以访问类的所有成员,包括private成员,当然访问过程需要通过类的对象进行。例如声明一个友元函数/类,有三种情况:
    ①友元是普通的全局函数
    一般情况下,使用一个函数需要先声明,或者定义在前,但是声明一个全局函数为友元函数的时候,可以理解为只是声明,而非调用,因此不用先在类的前面声明该全局函数。另外,如果要在类的前面声明该友元函数,需要用到类,因此还得在该声明的前面声明类的定义,比较麻烦。故总结顺序如下:类的定义,类中友元函数声明,类后友元函数实现。 这样的顺序应该万无一失了。

    #include<iostream>
    using namespace std;
    
    class student{
    	friend func(student *stu);//声明全局函数func为友元函数,不用在类前面声明,定义在后面。
    	private:
    		int age;
    //		void set_age(int t_age):age(t_age){};//不能使用初始化列表
    		void set_age(int t_age)
    		{
    			age = t_age;
    		 } 
    	public:
    		student(int t_age):age(t_age){};
    		void show_age(){cout<<"age = "<<age<<endl;};
    }; 
    void func(student *stu){
    	stu->set_age(-1); //可以通过对象访问private成员 
    	stu->show_age(); //当然也可以访问public成员
    }
    int main()
    {
    	student* stu = new student(10);
    	func(stu); //结果为: age = -1;
    	//查看age是否被修改
    	stu->show_age(); //结果为-1
    	//注意不能直接输出cout<<stu->age<<endl;
    	return 0;
    }
    

    这里刚开始的时候出了一个问题,set_age函数我使用了初始化列表,然后报错,搜查之后发现错误原因在于初始化列表的使用,注意:只有构造函数初始化的时候能使用初始化列表
    这里又发现了一个新的问题,在经过func函数之后,我想查看stu中的private成员age是否发生了变化,于是我试图通过直接输出age:

    cout << stu->age << endl;
    

    但是发现不可以,难道对象自己不能直接访问自己的私有数据成员么?
    查阅资料之后发现解释如下,private,public是针对类外的对象,类外的其他类对象的,这里stu定义在类外,因此不能访问私有数据成员。但是有一个例外,那就是友元函数,友元函数可以直接访问。而定义在类内的成员函数可以直接访问。总结一句话就是:在类内定义,可以访问,在类外定义,不能访问,友元函数可以访问
    ②友元是一个类
    同友元是一个函数一样,友元类可以先不定义,在当前类中声明友元类不会报错。所以顺序应该为:当前类的定义,类中声明友元类,友元类定义
    当然,如果先定义友元类,那么在友元类之前需要声明当前类。

    #include<iostream>
    using namespace std;
    
    class student {
    	friend class teacher; //声明一个友元类
    	//该友元类teacher还没有声明/定义,不会报错。
    private:
    	int age;
    	void set_age(int t_age);
    public:
    	student(int t_age) :age(t_age) {};
    	void show_age();
    };
    //友元类的实现
    class teacher {
    public:
    	teacher() {};
    	void func(student *stu); //如果把友元类定义在前,那么需要先声明student类,否则报错
    };
    void teacher::func(student* stu)
    {
    	stu->set_age(-1);
    	stu->show_age();
    }
    void student::set_age(int t_age)
    {
    	age = t_age;
    }
    void student::show_age()
    {
    	cout<<"age = "<<age<<endl;
    }
    int main()
    {
    	teacher* tea = new teacher();
    	student* stu = new student(10);
    	tea->func(stu); //age = -1
    	return 0;
    }
    

    ③友元是类中的一个成员函数
    这里需要注意的是:被声明为友元函数的成员函数必须定义在该类的前面,也就是这个成员函数所属的类在该类的前面定义,里面的成员函数可以只是先声明。也就是友元函数的类定义要在前面定义。但是问题来了,友元函数中的参数类型是当前类,所以得提前声明当前类。因此顺序为:当前类声明,友元类定义,当前类定义,两个类各种函数的具体实现。

    #include<iostream>
    using namespace std;
    class student; //必须提前声明,因为友元类中的函数要用到
    //友元函数所属类的定义必须在前,具体函数实现可以最后考虑
    class teacher {
    public:
    	teacher() {};
    	void func(student* stu); //友元函数
    };
    
    class student {
    	friend void teacher::func(student *stu); //声明一个类中的成员函数为友元函数
    private:
    	int age;
    	void set_age(int t_age);
    public:
    	student(int t_age) :age(t_age) {};
    	void show_age();
    };
    //两个类中的成员函数实现
    void teacher::func(student* stu)
    {
    	stu->set_age(-1);
    	stu->show_age();
    }
    void student::set_age(int t_age)
    {
    	age = t_age;
    }
    void student::show_age()
    {
    	cout<<"age = "<<age<<endl;
    }
    int main()
    {
    	student* stu = new student(10);
    	teacher* tea = new teacher();
    	tea->func(stu); //teacher类中的成员函数func被student类声明为友元函数,该函数可以访问student类所定义的对象的private成员
    
    	return 0;
    }
    
    

    最后需要注意两点:
    派生类中的友元函数对其基类不起作用,不能访问基类的private成员
    只有当某个类中的成员函数的定义都完整给出之后才能定义该类的对象。可以理解为,定义还没完成,无法确定存储空间大小,也就无法生成一个对象。

    展开全文
  • C++友元函数的定义和使用 <C++析构函数C++友元类> 类的封装性实现了数据隐藏,即类的私有成员在该类的作用域之外是不可见的。但有时可能需要在类的外部访问类的私有成员,为此 C++ 提供了一种允许类外的函数...

    本文参考:http://www.itxueyuan.org/view/100.html

    C++析构函数C++友元类 >

    类的封装性实现了数据隐藏,即类的私有成员在该类的作用域之外是不可见的。但有时可能需要在类的外部访问类的私有成员,为此 C++ 提供了一种允许类外的函数或其他的类访问该类的私有成员的方法,它通过关键字 friend 把其他类或函数声明为一个类的友元。

    友元的使用就好比一个独立的个人,私有成员是个人的秘密,本来对外界是保密的,但对于好朋友却没必要隐藏,这样好朋友就可以了解个人的所有秘密。在编程中,如果模拟空调和遥控器的程序,就可以使用友元关系来处理,遥控器不是空调或空调的一部分,但可以改变空调的状态。

    本节只讲解 C++ 友元函数,C++ 友元类将在下节讲解。

    友元函数是声明在类体内的一般函数,也可以是另一个类中的成员函数。友元函数并不是这个类中的函数,但它具有这个类中成员函数所具有的访问该类所有成员的功能。接下来分两种情况讨论友元函数。

    C++普通函数作为友元函数

    普通函数作为友元函数,其语法格式如下:

    friend 函数返回值类型 函数名(形式参数列表);


    接下来演示普通函数作为友元函数的用法,如例 1 所示。

    【例 1】

    #include <iostream>
    #include <cmath>
    using namespace std;
    class Point
    {
    public:
    Point(int a = 0, int b = 0)
    {
    x = a;
    y = b;
    }
    void print()
    {
    cout << "(" << x <<","<< y<< ")";
    }
    friend double Distance(Point a, Point b); //友元函数的声明
    private:
    int x, y;
    };
    double Distance(Point a, Point b) //友元函数的定义
    {
    int x = a.x - b.x;
    int y = a.y - b.y;
    return sqrt(x * x + y * y);
    }
    int main()
    {
    Point p1(3, 4), p2;
    double d = Distance(p1, p2); //友元函数的调用
    p1.print();
    p2.print();
    cout << " 距离为"<< d << endl;
    return 0;
    }

    程序执行结果为:

    (3,4)(0,0) 距离为5

    在例 1 中,Point 类中声明了一个友元函数,它是普通函数定义在类体外。友元函数中通过指定的对象访问了类中的私有数据成员,并进行了运算。

    C++类中的成员函数作为另一个类的友元函数

    类中的成员函数作为另一个类的友元函数,其语法格式如下:

    friend 类名::函数返回值类型 函数名(形式参数列表);


    接下来演示类中的成员函数作为另一个类的友元函数的用法,如例 2 所示。

    【例 2】

    #include <iostream>
    using namespace std;
    class B; //声明B类
    class A //定义A类
    {
    public:
    A(int x = 0)
    {
    a = x;
    }
    void print()
    {
    cout << "A: a = " << a << endl;
    }
    void func(B &var);
    private:
    int a;
    };
    class B //定义 B 类
    {
    public:
    B(int y = 0)
    {
    b = y;
    }
    void print()
    {
    cout << "B: b = " << b << endl;
    }
    friend void A::func(B &var); //将 A 类中的成员函数 func() 声明为 B 类的友元函数
    private:
    int b;
    };
    void A::func(B &var) //友元函数的定义
    {
    a = var.b;
    }
    int main()
    {
    A m(2);
    m.print();
    B y(3);
    y.print();
    m.func(y); //友元函数的调用
    m.print();
    return 0;
    }

    程序执行结果为:

    A: a = 2
    B: b = 3
    A: a = 3

    在例 2 中,第 3 行必须声明 B 类,因为只有 A 类完整定义过之后,才能定义友元的 B 类,而A类中又使用了“B”这个标识符,因此就需要使用类的声明。类的声明并不是对类的完整定义,它只是告诉编译器标识符的含义,一个只有声明的类是不能实例化的。

    在使用友元函数时,还需要注意以下几点:

    • 友元函数必须在类的定义中声明;
    • 友元函数的声明可以出现在类的任何地方,包括在 private 和 protected 部分;
    • C++ 不允许将某个类的构造函数、析构函数和虚函数声明为友元函数。
    • C++primer5th上250页说,不完全类型只能在以下情况使用(1)可以定义指向这种类型的指针或引用(2)可以声明(不能定义)以不完全类型作为参数或者返回类型的函数。

     

    我自己写了一个程序,证明不完全类型也可以声明指向它自己类型的引用。(估计定义指向它的指针也可以),如下:

    #include <iostream>
    #include <string>
    using namespace std;
    class Test{
    	public:
    		Test() = default;
    		Test(int k1,int k2):i(k1),j(k2){}
    		void print()const;
    		void fun(Test &t);//这里,Test还没没定义完,还是个不完全类型。结果通过编译
    	private:
    		int i;
    		int j;
    };
    void Test::print()const
    {
    cout << i << endl;
    cout << j << endl;
    }
    void Test::fun(Test &t)
    {
       if(i > 0) {cout << "first private data's sum:" << i + t.i<< endl;}
       if(j > 0) {cout <<"second private data's sum:."<< j+ t.j << endl;}
    }
    int main()
    {
    Test t1(1,2);
    Test t2(100,200);
    t1.print();
    t1.fun(t2);
    
    
    return 0;
    }

    结论,不完全类型可以声明它的引用。

    展开全文
  • 借助友元(friend),可以使得其他类中的成员函数以及全局范围内的函数访问当前类的 private 成员。friend 的意思是朋友,或者说是好友,与好友的关系显然要比一般人亲密一些。我们会对好朋友敞开心扉,倾诉自己的...
  • 友元函数与友元类

    2021-03-19 20:43:19
    友元函数的一些特点: 1.友元函数需要在类中任意位置进行声明,跟普通函数声明不同的是要加上friend 关键字,然后在类外进行实现,所以友元函数并不是类的成员函数。声明为友元函数之后,友元函数便可访问类中的私有...
  • 私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦。
  • 友元函数,友元类

    2020-04-17 22:37:13
    友元函数: 知识点1.友元函数的作用:该函数可以直接访问对象的私有数据成员 知识点2.现在假设有一个类A,有一个函数B,函数B在类A外(可以在其他类内,也可以是普通的全局函数),在类A中用friend对函数B进行声明,...
  • 输出流函数重载为成员方法以及全局函数 ①以下输出流重载为成员方法虽然解决了this指针抢占第一个参数的问题,但方法的调用必须用对象去驱动如下: t1 << cout ; 或 t1 << cout << endl; 这种...
  • 友元函数和友元类

    2021-05-26 22:40:49
    友元有:友元函数,友元成员,友元类 友元可以放在类的公有,私有,保护部分。 友元函数 1.友元函数可访问类的私有和保护成员,但不是类的成员函数 2.友元函数不能用const修饰 3.友元函数可以在类定义的任何地方...
  • 在c++中,经常会定义类。类有一个特点就是数据封装数据...使用友元函数将百分制学生的成绩转换成相应的分数等级。 #include<iostream> using namespace std; #include<iomanip> #include<string.h>
  • 一、友元函数 1.友元函数概述: (1)友元函数是定义在一个类外的普通函数。 友元函数和普通函数的定义一样;在类内必须将该普通函数声明为友元。 (2)友元函数不是成员函数。 不能通过对象来调用,而是直接调用;友元函数...
  • C++之中的友元函数的作用

    万次阅读 多人点赞 2017-12-09 17:23:22
    友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。通过友元,一个不同函数或另一个类中的成员函数可以访问类中的私有成员...友元函数友元函数是可以直接访问类的私有成员的非成员函
  • 在一个类中,可以利用关键字friend将其他的函数或类声明为友元,如果友元是一般函数或者类的成员函数,称为友元函数,如果友元是一个类,则成为友元类,友元类的所有成员函数都自动成为友元函数友元函数友元...
  • C 友元函数与友元类

    2019-10-05 23:55:08
    C++友元函数与友元类 在C++中,一个类中可以有public、protected、private三种属性的成员,通过对象可以访问public成员,只有本类中的函数可以访问本类的private成员。所以,通过友元(friend)能够打破封装性。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 46,147
精华内容 18,458
关键字:

友元函数