C++友元机制详解:全局函数、类和成员函数作为友元
一、友元机制概述
在C++中,友元(Friend)是一种特殊的机制,它允许一个类或函数访问另一个类的私有(private)和保护(protected)成员。友元打破了类的封装性,但有时这种"破坏"是必要的,特别是在需要提高某些特定函数或类的访问权限时。
友元的关键字是friend,C++支持三种友元形式:
- 全局函数作为友元
- 类作为友元
- 成员函数作为友元
二、全局函数作为友元
2.1 基本概念
全局函数作为友元是最简单的友元形式,它允许一个普通的全局函数访问类的私有成员。
2.2 代码示例
class People {
friend void friendVisit(People* p); // 声明全局函数为友元
public:
People() {
_house = "别墅";
_car = "法拉利";
}
public:
string _house;
private:
string _car;
};
// 全局函数定义
void friendVisit(People* p) {
cout << "好朋友来拆你的家啦!!!" << p->_house << endl;
cout << "好朋友来开你车啦!!!" << p->_car << endl; // 可以访问私有成员
}
2.3 特点分析
- 需要在类内部使用
friend关键字声明友元函数 - 友元函数不是类的成员函数,但可以访问类的所有成员
- 友元关系是单向的,不具有传递性
三、类作为友元
3.1 基本概念
当一个类被声明为另一个类的友元时,这个类的所有成员函数都可以访问另一个类的私有和保护成员。
3.2 代码示例
class People {
friend class peoplefriend; // 声明整个类为友元
public:
People() {
_house = "别墅";
_car = "法拉利";
}
public:
string _house;
private:
string _car;
};
class peoplefriend {
public:
void visit(People* p) {
cout << "好朋友来拆你的" << p->_house << endl;
cout << "好朋友来拆你的" << p->_car << endl; // 可以访问私有成员
}
};
3.3 特点分析
- 友元关系是单向的:A是B的友元,不意味着B是A的友元
- 友元关系不具有传递性:A是B的友元,B是C的友元,不意味着A是C的友元
- 友元关系不能被继承
四、成员函数作为友元
4.1 基本概念
这是最精细的友元控制方式,只允许另一个类的特定成员函数访问本类的私有成员。
4.2 代码示例
class People; // 前向声明
class peoplefriend1 {
public:
void visitall(People* p); // 将被声明为友元的成员函数
void visitpub(People* p); // 普通成员函数
};
class People {
friend void peoplefriend1::visitall(People* p); // 声明特定成员函数为友元
public:
People() {
_house = "别墅";
_car = "法拉利";
}
public:
string _house;
private:
string _car;
};
// 成员函数定义
void peoplefriend1::visitall(People* p) {
cout << "好朋友访问了你的" << p->_house << "并摧毁了它!!!" << endl;
cout << "好朋友访问了你的" << p->_car << "并摧毁了它!!!" << endl; // 可以访问私有成员
}
void peoplefriend1::visitpub(People* p) {
cout << "好朋友访问了你的" << p->_house << "并摧毁了它!!!" << endl;
// cout << p->_car << endl; // 错误!不能访问私有成员
}
4.3 特点分析
- 需要前向声明(forward declaration)
- 只能指定特定的成员函数为友元,其他成员函数不能访问私有成员
- 语法较为复杂,需要注意定义顺序
五、友元机制的注意事项
-
慎用友元:友元破坏了封装性,应谨慎使用。只有在确实需要让外部函数或类访问私有成员时才使用。
-
前向声明问题:在成员函数作为友元时,需要注意类的定义顺序,可能需要前向声明。
-
友元不可继承:友元关系不能被继承,基类的友元不是派生类的友元。
-
友元不可传递:A是B的友元,B是C的友元,并不意味着A是C的友元。
-
重载函数:如果需要将一组重载函数声明为友元,必须对每一个函数单独声明。
六、友元机制的应用场景
-
运算符重载:特别是需要访问私有成员的操作符重载,如<<、>>等。
-
某些工具函数:需要访问类内部状态但不适合作为成员函数的工具函数。
-
紧密协作的类:某些设计模式中,两个类需要紧密协作,可能需要互相访问私有成员。
-
测试代码:在单元测试中,测试代码可能需要访问被测类的私有成员。
七、总结
友元机制是C++中一种强大的特性,它提供了对类封装性的有限突破。合理使用友元可以提高代码的灵活性和效率,但过度使用会破坏面向对象的设计原则。开发者应当根据实际情况,权衡封装性和便利性,做出适当的设计选择。
在实际开发中,建议:
- 优先考虑使用公有成员函数提供接口
- 在确实需要时才使用友元
- 尽量使用最精细的访问控制(如成员函数友元而非整个类友元)
- 充分注释说明使用友元的原因
通过本文的详细讲解和代码示例,相信读者已经对C++的友元机制有了全面而深入的理解。在实际编程中,应根据具体需求合理运用这一特性。
八:源码及运行图
#include<iostream>
#include<string>
using namespace std;
/*全局函数作为友元
* 目的让一个类或函数可以访问另外一个类的私有成员
* 友元的关键字 friend
* 三种友元:
* 1.全局作为友元
* 2.类作为友元
* 3.成员函数作为友元
*/
/*
成员函数作为友元
//peoplefriend的某个函数可以访问 people的私有成员变量
*/
class People;//前向声明
class peoplefriend1// 1. 首先定义 peoplefriend1 类,但只声明其成员函数,将定义放在People类之后
{
public:peoplefriend1()
{
}
void visitall(People* p);
void visitpub(People* p);
};
class People
{
friend void peoplefriend1::visitall(People* p);
friend class peoplefriend;//加了下面类报错取消
friend void friendVisit(People* p);//加了以后下面报错取消
public:
People(){
_house = "别墅";
_car = "法拉利";
}
public:
string _house;
private:
string _car;
};
void friendVisit(People* p)
{
cout << "好朋友来拆你的家啦!!!"<<p->_house << endl;
cout << "好朋友来开你车啦!!!" <<p->_car<< endl;//报错无法访问,因为是私有成员
}
/*
类作为友元:
让一个类去访问另外一个类的私有成员
*/
class peoplefriend
{
public:peoplefriend()
{
}
void visit(People* p)
{
cout << "好朋友来拆你的" << p->_house << endl;
cout << "好朋友来拆你的" << p->_car << endl;//私有成员无法访问
}
};
void peoplefriend1::visitall(People* p)
{
cout << "好朋友访问了你的" << p->_house << "并摧毁了它!!!" << endl;
cout << "好朋友访问了你的" <<p->_car << "并摧毁了它!!!" << endl;
}
void peoplefriend1::visitpub(People* p)
{
cout << "好朋友访问了你的" << p->_house << "并摧毁了它!!!" << endl;
}
int main()
{
People p;
friendVisit(&p);//传入p的地址
peoplefriend p1;//实例化
p1.visit(&p);
peoplefriend1 p2;
p2.visitall(&p);
p2.visitpub(&p);
return 0;
}


更多推荐

所有评论(0)