精华内容
下载资源
问答
  • 前面提到了模板的声明和定义推荐都放在头文件中,那么该类中的友元函数的声明和定义该放在哪里呢?  因为友元函数并不属于这个类, 按照习惯,我们一般把声明放在类中,而把定义放在类的外面。但对于类模板来说,...

            前面提到了模板的声明和定义推荐都放在头文件中,那么该类中的友元函数的声明和定义该放在哪里呢?

            因为友元函数并不属于这个类, 按照习惯,我们一般把声明放在类中,而把定义放在类的外面。但对于类模板来说,这样就出问题了。很多编译器并不支持将友元函数的定义放在类的外面,会编译出错(一般是友元函数未定义)。故推荐按“inline”的形式定义类模板的友元函数。

    展开全文
  • C++使用类对数据进行隐藏封装,类数据成员一般定义为私有成员,而将提供类与外界通讯接口成员函数定义为公有。C++类成员三种访问权限:public:可以被该类中函数、子类函数、友元函数访问,也可以由该...

    C++使用类对数据进行隐藏和封装,类的数据成员一般定义为私有成员,而将提供类与外界通讯接口的成员函数定义为公有的。

    C++类成员的三种访问权限:

    • public:可以被该类中的函数、子类的函数、友元函数访问,也可以由该类的对象访问;
    • protected:可以被该类中的函数、子类的函数、友元函数访问,但不可以由该类的对象访问;
    • private:可以被该类中的函数、友元函数访问,但不可以由子类的函数、该类的对象、访问。

    但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁访问类的私有(private)成员和保护(protected)成员,这时可以将这些函数定义为友元函数。

    除了友元函数,还有友元类,两者统称为友元(friend)。

    借助友元,可以使得普通函数或其他类中的成员函数可以访问某个类的私有成员和保护成员。

    • 友元函数:普通函数可以访问某个类私有成员或保护成员。
    • 友元类:类A中的成员函数可以访问类B中的私有或保护成员。

    1、友元函数

    友元函数时可以直接访问类的私有成员或保护成员,它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明。

    友元函数的声明格式如下:

    friend 类型 函数名(形参);
    

    示例如下,友元函数 ShowAge() :

    8ab355a0fe80b22ce79f2d8f4da09600.png

    如上图所示,类的友元函数 ShowAge() 定义在类的外部,需要注意的是,尽管 ShowAge() 在类的定义中出现过,但其并不是类的成员函数。

    倘若没有在 Student 类中声明友元函数 ShowAge() ,则其是不能直接访问类的私有成员的,如下图所示。

    0eeef6be1e85bf6c18a5ba22bf29904e.png

    类的友元函数函数减少了类型检查和安全性检查,提高了程序的运行效率,但它破坏了类的封装性和隐藏性,使得非成员函数也可以访问类的私有成员。

    2、友元类

    友元可以是一个函数,也可以是一个类,该类被称为友元类。

    友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的保护成员和私有成员。

    声明友元类的格式如下:

    friend class 类名;
    

    其中,friend 和 class 是关键字,类名必须是程序中已经定义过的一个类。

    示例如下,类CB是类CA的友元类,可以直接访问类CA的私有成员。

    4ac3f93befac6015368567de50f4df21.png

    倘若没有在类CA中声明友元类CB,则CB是不能直接访问CA的私有成员的。

    2ce3a1b46632bb3522ccd6cc120a74f0.png

    使用友元类时,需要注意:

    • 友元关系不能被继承;
    • 友元关系是单向的,不具有交换性。即类B是类A的友元,则类A不一定是类B的友元,需要看类中是否有相应的声明;
    • 友元关系不具有传递性。即类B是类A的友元,类C是类B的友元,但类C不一定是类A的友元,需要看类中是否有相应的声明。

    另外,使用一般不建议把整个类声明为友元类,而只将某些成员函数声明为友元函数,这样更安全些。

    3、友元的优缺点

    利用 friend 修饰符,可以让一些普通函数 或 另一个类的成员函数 直接对某个类的保护成员和私有成员进行操作,提高了程序的运行效率;同时避免把类的成员都声明为public,最大限度地保护数据成员的安全。

    但是,即使是最大限度地保护数据成员,友元也破坏了类的封装性。

    如果将类的封装比喻成一堵墙的话,那么友元机制就像墙上开了一个门。所以使用友元时一定要慎重。

    展开全文
  • 一般情况下,使用一个函数需要先声明,或者定义在前,但是声明一个全局函数为友元函数的时候,可以理解为只是声明,而非调用,因此不用先在类的前面声明该全局函数。另外,如果要在类的前面声明该友元函数,需要用到...

    友元声明

    前面加上关键字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++中基本的友元函数用法,包括...其中,友元函数的声明跟平常函数声明基本一样,只需要在函数声明前加一个friend就行,友元函数的定义跟普通函数定义一模一样(不需要指定类作用域运算符),下面是...

    本文主要总结一个C++中基本的友元函数用法,包括友元函数声明和定义、一个应用简单例子和编译结果,友元函数特性总结,下面是具体讲述。

    1.1友元函数声明和定义

    首先友元函数是声明在类中的,作用是可以反问该类的私有成员(成员函数和成员参数)。其中,友元函数的声明跟平常函数声明基本一样,只需要在函数声明前加一个friend就行,友元函数的定义跟普通函数定义一模一样(不需要指定类作用域运算符),下面是一个典型的友元函数声明和定义。

    #include <iostream>
    
    //友元函数在类中声明
    friend ostream & operator<<(ostream &os, const CFriendClass &friendClass);
    
    
    //友元函数在类中定义,不能用作用域解析运算符,因为友元函数不是成员函数,也不能被继承
    ostream & operator<<(ostream &os, const CFriendClass &friendObject)
    {
    	//友元函数访问私有成员变量,但是不能直接在定义友元函数时调用私有成员变量,只能通过引用类对象的成员参数方式调用
    	os << "operator friendObject.value==" << friendObject.value << endl;
    	return os;
    }

    1.2友元函数应用简单例子

    在vs2013新建一个console空白工程,分别在文件FriendClass.h,FriendClass.cpp,main.cpp中添加如下代码

    FriendClass.h(编译环境vs2013 console工程)

    #pragma once
    #include <iostream>
    
    using std::ostream;
    
    class CFriendClass
    {
    public:
    	CFriendClass();
    	~CFriendClass();
    
    	friend int getValue(CFriendClass &friendObject);
    	friend ostream & operator<<(ostream &os, const CFriendClass &friendObject);
    
    private:
    	int value;
    };

     

    FriendClass.cpp

    #include "FriendClass.h"
    
    using std::cout;
    using std::endl;
    
    CFriendClass::CFriendClass() :value(66)
    {	
    }
    
    int getValue(CFriendClass &friendObject)
    {
    	//友元函数访问私有成员变量,但是不能直接在定义友元函数时调用私有成员变量,只能通过引用类对象的成员参数方式调用
    	cout << "getValue value==" << friendObject.value<<endl;
    	return friendObject.value;
    }
    
    ostream & operator<<(ostream &os, const CFriendClass &friendObject)
    {
    	//友元函数访问私有成员变量,但是不能直接在定义友元函数时调用私有成员变量,只能通过引用类对象的成员参数方式调用
    	os << "operator friendObject.value==" << friendObject.value << endl;
    	return os;
    }
    
    CFriendClass::~CFriendClass()
    {
    }
    

     

    main.cpp

    #include <iostream>
    #include <string>
    #include "FriendClass.h"
    
    /*using编译指令还可以在派生类中显示声明基类成员,包括私有成员函数和私有成员参数,声明后,在派生类中可以调用基类私有成员*/
    using std::cout;
    using std::endl;
    using std::string;
    
    int main()
    {
    	//友元函数访问私有成员变量,但是不能直接在定义友元函数时调用私有成员变量,只能通过引用类对象的成员参数方式调用
    	CFriendClass friendObject;
    	getValue(friendObject);
    
    	cout << "friendObject==" << friendObject << endl;
    
    	cout << string("this is a string!");
    
    	getchar();
    
    	return 0;
    }

    1.3编译运行结果

    1.4友元函数特性总结

    由上面示例代码可知,友元函数访问类的私有成员,是通过类的引用来调用类的私有成员。

    a1 成员函数不能直接调用类的私有成员,而是要通过引用或者指针来调用类的私有成员。

    a2 友元函数不是类的成员函数,不能用作用域解析运算符操作

    a3 友元函数因为不是成员函数,不能被派生类继承

    当执行代码cout << "friendObject==" << friendObject << endl;,也就是执行cout << friendObject时,实际是执行操作运算符cout.operator(friendObject),即调用了友元函数ostream & operator<<(ostream &os, const CFriendClass &friendObject)。要注意前后顺序,不能将友元函数中的成员参数顺序颠倒(ostream & operator<<(const CFriendClass &friendObject, ostream &os)),否则出现friendObject.operator(cout),则调用错误!!!

     

    参考内容:

    《C++ Primer Plus》(第6版)中文版  539-542页(参考:友元声明和定义,调用实例)

    https://blog.csdn.net/qq_26337701/article/details/53996104(参考:友元函数调用)

    https://blog.csdn.net/qq_29511193/article/details/77131203(参考:友元函数声明和定义)

    展开全文
  • C++中的友元函数

    2018-02-25 23:04:48
    如果在类的声明中定义友元函数(即友元函数的声明和定义放在一处,都在类内部),则此友元函数为内联函数,即使没有使用inline关键字,且此友元函数的作用域为文件范围,而非类范围,调用此友元函数时也无需带“类名::...
  • 友元函数和友元类声明举例

    千次阅读 2014-12-08 15:57:29
    注: 友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。...即友元函数的声明可以出现在类的任何地方 class A {
  • 友元函数的声明位置 首先必须是在类中 至于是在public,protected,private无所谓,外接都可以直接调用 友元函数的实现位置,也就是具体的定义(非声明)所在位置 第1种方式(推荐):在宿主类中声明的同时直接提供定义 ...
  • 友元类和友元函数

    2021-05-06 16:10:28
    友元函数和普通函数最大区别在于友元函数可以直接访问类私有成员保护成员; 友元函数不属于类成员函数,但是友元函数必须在类内部定义友元函数使用friend关键词声明友元函数能够实现类之间数据共享...
  • 友元 一般来说,类公有成员能够在类外访问,私有成员只能被类其他成员函数...C++提供一种允许外部类函数存取类私有成员保护成员辅助方法,即将它们声明为一个给定类友元(或友元函数),使其具有类成
  • 在类外定义的函数,可以在在类内进行声明,但要在前面加上关键字friend,这样就构成了友元函数 友元函数可以是不属于任何类成员函数,也可以是其他类成员函数 友元函数可以访当前类中所有成员(private、...
  • 友元函数和友元类

    2020-02-29 14:42:04
    友元 c++由于封装特性只有类中成员函数可以访问private类型成员变量。通过友元可以使其他类中成员函数或不...友元函数可以在类定义的任何地方声明,不受类访问限定符限制 友元函数不同于类成员函数,在友...
  • //友元函数:如果在一个类外面定义了一个函数(该函数不属于这个类),当类中用friend对该函数进行声明后, 该函数就可以访问类中所有成员. //友元函数分为:将普通函数声明友元函数,将其他类中成员函数声明友元...
  • 友元函数和友元成员函数 #include using namespace std; class Boy;//提前声明,否则下面函数声明没有办法定义: class Girl { private: int age; public: Girl(int a) { age = a; } ~Girl() { cout << ...
  • 友元(友元函数、友元类友元成员函数) C++ 有些情况下,允许特定非成员函数访问一个类私有成员,同时仍阻止一般访问,这是很方便做到。例如被重载操作符,如输入或输出操作符,经常需要访问类私有数据...
  • C++中的友元函数友元类 在C++中类具有封装的隐蔽性,由于语言特性,只有...友元分为友元函数友元类,友元函数就是非成员函数可是当我们声明友元函数的时候也可以访问类中的私有成员,友元类就是可以访问另一...
  • 友元的作用:提高了程序的运行效率(使得普通函数可以直接访问类的保护数据,避免了类成员函数的频繁调用,即减少了类型检查安全性检查等都需要时间开销),但它破坏了类的封装性隐藏性,使得非成员函数可以访问...
  • 友元(友元函数、友元类友元成员函数) C++ 有些情况下,允许特定非成员函数访问一个类私有成员,同时仍阻止一般访问,这是很方便做到。例如被重载操作符,如输入或输出操作符,经常需要访问类...
  • C++友元函数和友元类

    2020-08-03 12:20:55
    尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。 友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。 如果要...
  • 友元函数

    2013-04-26 22:07:44
    #include #include class Student { private: ... friend void show(Student&st) //友元函数的声明和定义  {  cout  } public:  Student(char *s1,char *s2)  {  strcpy(name,s1);
  • 文章目录声明成员函数友元函数类模板内实现重新定义一个函数模板 声明 类模板的声明语法如下 template<typename 类型参数, typename 类型参数, ...> class className { //TODO; } 这里面的typename相当于一种...
  • 当一个类被包含一个友元声明的时候,类和友元是否是模板是相互无关。 如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例; 如果友元自身是模板,类可以授权给所有友元模板实例,也可以之授权给...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 882
精华内容 352
关键字:

友元函数的声明和定义