友元函数和友元类
目录:
一:什么是友元?
在C++中,友元(friend)是一种机制,允许一个类(或函数)访问另一个类的私有成员,即使这些私有成员在正常情况下是不可访问的。 友元关系是通过在一个类中声明另一个类(或函数)为友元来建立的。这样,被声明为友元的类(或函数)就可以在需要时访问该类的私有成员。
注意:
友元的存在是为了在某些特殊情况下提供灵活性和控制,但过度使用友元可能破坏封装性,因此需要谨慎使用。
友元特点:
1. 友元关系是单向的:A类是B类的友元并不代表B类是A类的友元。
2. 友元关系不可传递(继承):即如果A类是B类的友元,B类是C类的友元,那么A类不一定是C类的友元。
二:友元的使用方式
友元有以下几种形式:
友元函数:一个函数被声明为另一个类的友元函数,那么该函数可以访问该类的私有成员。这在需要进行一些与类紧密相关的操作,但又不适合将其作为类成员函数的情况下非常有用。
友元类:一个类被声明为另一个类的友元类,那么该类的所有成员函数都可以访问另一个类的私有成员。这在需要两个类之间的深度数据共享时非常有用。
(1)全局函数做友元
1. 使用方法:
调用类中的私有成员时,可以在类中声明该函数,并在前面加上friend 做友元。
2. 语法:
friend 返回值类型 全局函数();
3. 无参和有参全局函数做友元案例:
class Person {
private:
int* m_Salary;
int m_Age;
public:
friend void printInfo(const Person &p); // 全局有参函数声明友元
friend void printInfo(); // 全局无参函数声明友元
Person() {} // 默认构造函数
Person(int age,int salary){ // 有参构造函数
this->m_Age = age;
m_Salary = new int(salary);
}
~Person(){ // 析构函数
if (m_Salary != NULL){
delete m_Salary;
m_Salary = NULL;
}
}
};
//全局函数做友元
void printInfo(const Person& p){
cout << "年龄:" << p.m_Age << " 薪水:" << *p.m_Salary << "w" << endl;
}
// 无参全局函数做友元
void printInfo(){
Person p1(23, 40);
cout << "年龄:" << p1.m_Age << " 薪水:" << *p1.m_Salary << "w" << endl;
}
// 测试
int main(){
Person p1(25,20);
printInfo(p1);
printInfo();
}
输出结果:
年龄:25 薪水:20w
年龄:23 薪水:40w
以上示例是全局函数 printInfo(const Person& p) 和 printInfo() 来做Person类的友元函数,可以用来访问Person类内的私有成员。
(2)成员函数做友元
1. 目的:
A类的成员函数需要访问B类的私有成员。
2. 解决办法:
需要在B类中声明A类作用域下的成员函数,添加friend关键字让该成员函数做B类的友元成员函数。
3. 语法:
friend 返回值类型 类名::成员函数();
4. 注意:
友元函数的声明和实现:当一个类的成员函数作为另一个类的友元函数时,应该先在类的内部声明该成员函数,然后在类的外部实现它。 这是因为在定义友元关系时,需要确保编译器已经知道友元函数的存在和接口。类的定义在编译时的前向声明通常不足以满足这一要求,因此最佳做法是在类的内部进行函数的声明,然后在类的外部进行函数的实现。
5. 成员函数做友元案例:
//声明Person类 和 A类的visit()该成员函数将作为Person类的友元函数
class Person;
class A {
public:
void visit(const Person& p); //定义该函数
};
class Person {
private:
int* m_Salary;
int m_Age;
public:
Person(int age,int salary): m_Age(age),m_Salary(new int(salary)){}
~Person(){
if (m_Salary != NULL)
{
delete m_Salary;
m_Salary = NULL;
}
}
friend void A::visit(const Person& p); //声明 A 的成员函数作为友元,需要指明哪个作用域下的成员函数
};
void A::visit(const Person& p) {
cout << "年龄:" << p.m_Age << " 薪水:" << *p.m_Salary << "w" << endl; // 通过该友元函数获取Person类的私有成员的值
}
int main()
{
Person p1(25,20);
A a;
a.visit(p1);
return 0;
}
输出结果:
年龄:25 薪水:20w
以上示例展示了如何在类的内外分别声明和实现友元函数:
- 声明Person类和A的成员函数:首先,在第一个类(A) 的定义之前,你需要声明另一个类(Person)。这个声明告诉编译器,有另一个类存在,即将要使用它。同时,在第一个类中声明一个成员函数作为友元函数,这个函数将访问另一个类的私有成员。
- 定义类:然后,定义第一个类的成员函数和其他部分。在第一个类的定义中,你只需要知道第二个类的存在,不需要关注具体的实现细节。
- 定义另一个类:接着,在第二个类的定义中,你可以定义它的私有成员和其他成员函数。
- 定义友元函数:最后,在类的定义之后,实现第一个类中声明的友元函数。这个函数将能够访问第二个类的私有成员,因为你在第一个类中声明了友元关系。
这个过程确保了类之间的依赖关系和访问权限的正确处理,使得一个类可以在需要时访问另一个类的私有成员,同时保持了良好的封装性和代码可读性。
(3)类做友元(友元类)
1. 语法:
friend class 类名;
2. 类做友元的代码案例:
class Person {
private:
int* m_Salary;
int m_Age;
public:
Person(int age,int salary): m_Age(age),m_Salary(new int(salary)){}
~Person(){
if (m_Salary != NULL)
{
delete m_Salary;
m_Salary = NULL;
}
}
friend class A; // 声明 A 为友元类
};
class A {
public:
void visit(const Person& p);
};
void A::visit(const Person& p) {
cout << "年龄:" << p.m_Age << " 薪水:" << *p.m_Salary << "w" << endl;
}
int main()
{
Person p1(25,20);
A a;
a.visit(p1);
return 0;
}
输出结果:
年龄:25 薪水:20w
三:总结:
以上就是友元的使用形式和方式的实际操作。
注意:友元的使用应该谨慎,因为它会降低类的封装性和可维护性。过度使用友元可能会导致代码紧密耦合,增加了代码的复杂性和不可预测性。通常情况下,应该优先考虑使用类的公有接口来操作数据,而不是通过友元来直接访问私有成员。
希望大家多多支持,码字不易,若有错误请指出,共同学习!
欢迎关注🔎点赞👍收藏⭐️留言📝