C++友元知识点详解

1.何为友元?

类可以允许其他类或者函数访问它的非公有成员(通过类的对象),方式是令其他类或者函数成为它的友元(需要用到friend关键字)。

2.友元分类

3.非成员函数作为友元函数

示例代码结构如下:

// Student.hpp

#ifndef STUDENT_HPP
#define STUDENT_HPP

class Student {
public:

    friend void ModifyAge( Student &stu, int value );
    Student():age(18){}
    ~Student(){}
    int GetAge(){
        return age;
    }
    void SetAge( int tmp ){
        age = tmp;
    }
private:
    int age;   
};
void ModifyAge( Student &stu, int value );
#endif /* STUDENT_HPP */

// Student.cpp

#include "Student.hpp"

void ModifyAge( Student &stu, int value ){
    stu.age = value;
}
// main.cpp


#include <iostream>
#include "Student.hpp"

using namespace std;


int main( void ){
    Student a;
    cout << a.GetAge() << endl;
    ModifyAge( a, 25 );
    cout << a.GetAge() << endl;
    return 0;
}

友元声明只能出现在类定义的内部,但是在类内出现的具体位置没有限制。

并且友元不是类的成员,不受它所在区域,访问控制级别的约束(不受public,private的约束)。

特别注意:友元声明仅仅是指定了访问权限,也就是告诉Student这个类,ModifyAge可以访问age这个私有数据成员。类定义中 ModifyAge函数的友元声明,并不是普通意义上的函数声明。因此,在类定义的外部,我们单独对ModifyAge函数进行了声明(注意这里没有用friend关键字)。

如果我们没有在类的外部对ModifyAge函数进行声明,main.cpp的内容如下所示:

// main.cpp

#include <iostream>


class Student {
friend void ModifyAge( Student &stu, int value );

public:
    Student():age(18){}
    ~Student(){}

    int GetAge(){
        return age;
    }

    void SetAge( int tmp ){
        age = tmp;
    }

private:
    int age;   
};


using namespace std;

int main( void ){
    Student a;
    cout << a.GetAge() << endl;
    ModifyAge( a, 25 );			// 这里在编译时会报错,在当前文件中,找不到ModifyAge函数的声明
    cout << a.GetAge() << endl;
    return 0;
}

许多编译器并未强制要求友元函数必须在使用之前在类的外部声明。上述错误,不一定在你的编译环境中会复现。但是,出于代码的可移植性,我们最好还是在类定义的外部,单独对友元函数进行声明。

4.类是友元

示例代码结构如下:

// Student.hpp


#ifndef STUDENT_HPP
#define STUDENT_HPP


class Student {
friend class Teacher;

public:
    Student():age(18){}
    ~Student(){}

    int GetAge(){
        return age;
    }

    void SetAge( int tmp ){
        age = tmp;
    }
private:

    int age;   
};
#endif /* STUDENT_HPP */
// Teacher.hpp



#ifndef TEACHER_HPP
#define TEACHER_HPP

#include "Student.hpp"

class Teacher {
public:
    Teacher() = default;
    virtual ~Teacher();
    void SetStudentAge( Student &stu, int value );
private:

};

#endif /* TEACHER_HPP */
// Teacher.cpp


#include "Teacher.hpp"


Teacher::~Teacher() {
}


void Teacher::SetStudentAge( Student &stu, int value ){
    stu.age = value;
}
// main.cpp


#include <iostream>
#include "Student.hpp"
#include "Teacher.hpp"

using namespace std;

int main( void ){
    Student a;
    cout << a.GetAge() << endl;
    
    Teacher t1;
    t1.SetStudentAge(a,30);
    cout << a.GetAge() << endl;
        
    return 0;
}

5.类的成员函数是友元

示例代码结构如下:

// Student.hpp

#ifndef STUDENT_HPP
#define STUDENT_HPP

// 这里包含Teacher1的头文件,是因为友元声明中用到了Teacher1::
#include "Teacher1.hpp"

class Student {
friend void Teacher1::SetStuAge( Student &stu, int value );

public:
    Student():age(18){}
    ~Student(){}

    int GetAge(){
        return age;
    }

    void SetAge( int tmp ){
        age = tmp;
    }

private:
    int age;   
};
#endif /* STUDENT_HPP */

// Teacher1.hpp

#ifndef TEACHER1_HPP
#define TEACHER1_HPP

// 注意:这里没有包含Student的头文件
// 这里用的是不完全类型(C语言中结构的不完整声明)
class Student;

class Teacher1 {
public:
    Teacher1();
    void SetStuAge( Student &stu, int value );
    virtual ~Teacher1();
private:

};

#endif /* TEACHER1_HPP */
// Teacher1.cpp


#include "Teacher1.hpp"
#include "Student.hpp"    // 这里包含了Student头文件
Teacher1::Teacher1() {
}


Teacher1::~Teacher1() {
}


void Teacher1::SetStuAge( Student &stu, int value ){
    stu.age = value;
}
// main.cpp

#include <iostream>
#include "Student.hpp"
#include "Teacher1.hpp"

using namespace std;

int main( void ){
    Student a;
    cout << a.GetAge() << endl;

    Teacher1 t2;
    t2.SetStuAge(a,35);
    cout << a.GetAge() << endl;
    
    return 0;
}

到这里三种友元类型的示例都展示完成了。

最不好理解的就是成员函数作为友元的情况,需要组织好类的结构,不然编译时,很容易报错。

下面对第三种情况做一个总结。

类B有一个成员函数B::func(),是类A的友元,那么三者需要按照下面的顺序进行组织:

  • 首先定义类B,声明func函数,但是不能定义它。同时需要在定义类B之前,声明类A(不完整声明)。
  • 定义类A,包括对B::func函数的友元声明(#include "B.hpp")。
  • 最后定义B::func,此时它才可以使用类A的私有成员。

6.注意事项

  • 友元是为了兼顾 C 语言的高效而诞生的(通过对象直接访问私有数据成员,不需要再使用成员函数去访问私有数据成员,减少了函数调用的开销)
  • 友元直接破坏了面向对象的封装性
  • 友元关系不具备传递性
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值