大话C++:第15篇 友元
友元(Friend)是C++中的一个特殊概念,它允许一个类或函数访问另一个类的私有和保护成员。友元可以是一个函数,也可以是一个类。
1 友元函数
友元函数(Friend Function)是C++中的一个特殊概念,它允许一个非成员函数访问类的私有(private)和受保护(protected)成员。友元函数不是类的成员函数,但它们被授权可以像类的成员函数一样访问类的私有和保护成员。通常,只有类的成员函数和友元函数能够访问类的私有和保护成员。
在C++中,友元函数的声明语法格式通常是在类的定义中,使用friend
关键字后跟函数的声明。
#include <iostream>class Person
{
public:Person(int age) : _age(age) {}// 声明一个友元函数friend void DisplayPrivateInfo(Person& obj);private:// 私有成员变量int _age;
};// 定义友元函数
void DisplayPrivateInfo(Person& obj)
{// 尽管_age是私有的,友元函数仍然可以访问它std::cout << "对象的年龄: " << obj._age << std::endl;
}int main()
{Person jack(42);// 输出jack的年龄DisplayPrivateInfo(jack);return 0;
}
注意,
-
友元函数可以定义在类的外部,也可以在类的内部定义,但通常的做法是在类的外部定义友元函数,以保持类的定义更加清晰。
-
友元函数破坏了类的封装性,因此在设计类时应谨慎使用友元函数,只有在确实需要时才应使用。通常,更好的做法是通过类的公有成员函数来访问和修改私有成员,以保持类的封装性和隐藏性。
2 友元类
当一个类被声明为另一个类的友元时,这个类的所有成员函数都可以访问另一个类的私有(private)和受保护(protected)成员。这种关系被称为“友元类”(Friend Class)。
友元类的声明语法格式:
class ClassA
{// ... 类A的成员 ...// 声明ClassB为ClassA的友元类friend class ClassB;
};class ClassB
{// ... 类B的成员 ...// ClassB的成员函数可以访问ClassA的私有和受保护成员void AccessClassAMembers(ClassA& a) {// 可以直接访问ClassA的私有和受保护成员std::cout << a.privateMemberOfA << std::endl;a.protectedMemberOfA = 42;}
};
其中,ClassB
被声明为ClassA
的友元类。因此,ClassB
中的所有成员函数都可以访问ClassA
的私有和受保护成员。需要注意的是,友元关系不是相互的,即使ClassB
是ClassA
的友元类,ClassA
也不一定是ClassB
的友元类,除非在ClassA
中也进行了相应的友元类声明。
#include <iostream>// 声明ClassB为ClassA的友元类
class ClassA
{friend class ClassB; // ClassB被声明为ClassA的友元类private:// 私有成员变量int privateVar;public:// 构造函数ClassA(int value) : privateVar(value) {}// 公有成员函数void SetPrivateVar(int value) {privateVar = value;}// 获取私有成员变量的值(通常应该避免这样做,但为了示例而包含)int GetPrivateVar() const {return privateVar;}
};// ClassB,它是ClassA的友元类
class ClassB
{
public:// ClassB的成员函数可以直接访问ClassA的私有成员void AccessAndModifyClassA(ClassA& a) {// 直接访问并修改ClassA的私有成员std::cout << "修改前,privateVar: " << a.GetPrivateVar() << std::endl;a.privateVar = 42; // 直接修改私有成员std::cout << "修改后,privateVar: " << a.GetPrivateVar() << std::endl;}
};int main()
{// 创建ClassA的对象ClassA a(10);// 创建ClassB的对象ClassB b;// 使用ClassB的对象来访问和修改ClassA的私有成员b.AccessAndModifyClassA(a);return 0;
}
注意,友元类破坏了类的封装性和隐藏性,因此应该谨慎使用。它们通常只在确实需要访问另一个类的私有成员时才被声明为友元类。在大多数情况下,更好的做法是通过类的公有成员函数来访问和修改私有成员,以保持类的封装性和隐藏性。
3 友元注意事项
由于友元可以突破类的封装性和隐藏性,因此在使用时需要特别注意以下几点:
-
非对称性:友元关系不是对称的。如果类B是类A的友元,并不意味着类A自动成为类B的友元。需要在类A中也声明类B为友元,才能建立对称的友元关系。
-
非传递性:友元关系不具有传递性。如果类B是类A的友元,类C是类B的友元,并不意味着类C自动成为类A的友元。需要在类A中明确声明类C为友元,才能建立类C和类A之间的友元关系。
-
谨慎使用:由于友元可以访问类的私有成员,这破坏了类的封装性和隐藏性。因此,应该谨慎使用友元,只有在确实需要时才应声明友元。通常,更好的做法是通过类的公有成员函数来访问和修改私有成员。
-
避免过度使用:过度使用友元可能导致代码难以理解和维护。如果一个类有许多友元类或函数,那么它的封装性可能已经被破坏,这可能会导致潜在的安全风险和维护问题。
-
明确声明:友元关系需要在类定义中明确声明。不论是友元函数还是友元类,都需要在相应的类中使用
friend
关键字进行声明。 -
注意命名冲突:由于友元函数或类不是类的成员,它们可能与其他全局函数或类产生命名冲突。因此,在命名友元函数或类时,应该选择具有描述性和唯一性的名称,以避免潜在的命名冲突。
-
考虑替代方案:在决定使用友元之前,应该考虑是否有其他替代方案可以实现相同的功能,同时保持类的封装性和隐藏性。例如,可以考虑使用公有成员函数和参数来访问和修改私有成员