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;
}
private:
void SetAge( int tmp ){
age = tmp;
}
int age;
};
void ModifyAge( Student &stu, int value );
#endif /* STUDENT_HPP */
// Student.cpp
#include "Student.hpp"
void ModifyAge( Student &stu, int value ){
stu.SetAge(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>
//#include "Student.hpp" Student.hpp替换为下面的内容
class Student {
public:
friend void ModifyAge( Student &stu, int value );
Student():age(18){}
~Student(){}
int GetAge(){
return age;
}
private:
void SetAge( int tmp ){
age = tmp;
}
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 {
public:
friend class Teacher;
Student():age(18){}
~Student(){}
int GetAge(){
return age;
}
private:
void SetAge( int tmp ){
age = tmp;
}
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.SetAge(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 {
public:
friend void Teacher1::SetStuAge( Student &stu, int value );
Student():age(18){}
~Student(){}
int GetAge(){
return age;
}
private:
void SetAge( int tmp ){
age = tmp;
}
int age;
};
#endif /* STUDENT_HPP */
// Teacher1.hpp
#ifndef TEACHER1_HPP
#define TEACHER1_HPP
// 注意:这里没有包含Student的头文件
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.SetAge(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的私有成员。
|