一个类的成员函数声明为另一个类的友元函数

本文深入探讨了C++中的友元机制,包括友元函数和友元类的概念及其使用方法。介绍了如何利用友元机制实现不同类之间的数据共享,并讨论了其对封装性和数据隐藏性的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。通过友元,一个不同函数或另一个类中的成员函数可以访问类中的私有成员和保护成员。c++中的友元为封装隐藏这堵不透明的墙开了一个小孔,外界可以通过这个小孔窥视内部的秘密。

友元的正确使用能提高程序的运行效率,但同时也破坏了类的封装性和数据的隐藏性,导致程序可维护性变差。

友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。通过友元,一个不同函数或另一个类中的成员函数可以访问类中的私有成员和保护成员。c++中的友元为封装隐藏这堵不透明的墙开了一个小孔,外界可以通过这个小孔窥视内部的秘密。

友元的正确使用能提高程序的运行效率,但同时也破坏了类的封装性和数据的隐藏性,导致程序可维护性变差。

友元函数 :

友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:

friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。


友元类 :
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

1: #include <iostream>
2: using namespace std;
3:
4: class Radius
5: {
6: friend class Circle; //声明Circle为Radius的友元类
7: friend void Show_r(Radius &n); //声明Show_r为友元函数
8: public:
9: Radius(int x)
10: {
11: r = x;
12: }
13: ~Radius()
14: {
15: }
16:
17: private:
18: int r;
19: };
20:
21: void Show_r(Radius &n)
22: {
23: cout<<"圆的半径为: "<<n.r<<endl; //调用Radius对象的私有成员变量r
24: }
25:
26: class Circle
27: {
28: public:
29: Circle() {}
30: ~Circle(){}
31: double area(Radius a)
32: {
33: s = a.r * a.r * 3.1415926; //调用Radius对象的私有成员变量r
34: return s;
35: }
36: private:
37: double s;
38: };
39:
40: int main(int argc, char *argv[])
41: {
42: Radius objRadius(9);
43: Circle objCircle;
44:
45: Show_r( objRadius );
46: cout<<"面积为:"<<objCircle.area(objRadius)<<endl;
47:
48: return 0;
49: }
被声明两个类的友元声明

如果我们决定一个函数必须被声明为两个类的友元则友元声明如下

1: class Window; // 只声明
2:
3: class Screen
4:
5: {
6:
7: friend bool is_equal( Screen &, Window & );
8:
9: // ...
10:
11: };
12:
13: class Window
14:
15: {
16:
17: friend bool is_equal( Screen &, Window & );
18:
19: // ...
20:
21: };
作为一个类的函数又是另一个类的友元

如果我们决定该函数必须作为一个类的成员函数并又是另一个类的友元,则成员函数声明和友元声明如下:

1: class Window;
2:
3: class Screen
4:
5: {
6:
7: public:
8:
9: // copy 是类 Screen 的成员
10:
11: Screen& copy( Window & );
12:
13: // ...
14:
15: };
16:
17: class Window
18:
19: {
20:
21: // copy 是类 Window 的一个友元
22:
23: friend Screen& Screen::copy( Window & );
24:
25: // ...
26:
27: };
只有当一个类的定义已经被看到时它的成员函数才能被声明为另一个类的友元。这并不总是能够做到的。

例如如果Screen 类必须把Window 类的成员函数声明为友元,而Window类必须把Screen 类的成员函数声明为友元。该怎么办呢?在这种情况下可以把整个Window类声明为Screen 类的友元。

例如:



1: class Window;
2:
3: class Screen
4:
5: {
6:
7: friend class Window;
8:
9: // ...
10:
11: };
Screen 类的非公有成员现在可以被Window 的每个成员函数访问。

使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明友元函数 :

友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:

friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。


友元类 :
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

1: #include <iostream>
2: using namespace std;
3:
4: class Radius
5: {
6: friend class Circle; //声明Circle为Radius的友元类
7: friend void Show_r(Radius &n); //声明Show_r为友元函数
8: public:
9: Radius(int x)
10: {
11: r = x;
12: }
13: ~Radius()
14: {
15: }
16:
17: private:
18: int r;
19: };
20:
21: void Show_r(Radius &n)
22: {
23: cout<<"圆的半径为: "<<n.r<<endl; //调用Radius对象的私有成员变量r
24: }
25:
26: class Circle
27: {
28: public:
29: Circle() {}
30: ~Circle(){}
31: double area(Radius a)
32: {
33: s = a.r * a.r * 3.1415926; //调用Radius对象的私有成员变量r
34: return s;
35: }
36: private:
37: double s;
38: };
39:
40: int main(int argc, char *argv[])
41: {
42: Radius objRadius(9);
43: Circle objCircle;
44:
45: Show_r( objRadius );
46: cout<<"面积为:"<<objCircle.area(objRadius)<<endl;
47:
48: return 0;
49: }
被声明两个类的友元声明

如果我们决定一个函数必须被声明为两个类的友元则友元声明如下

1: class Window; // 只声明
2:
3: class Screen
4:
5: {
6:
7: friend bool is_equal( Screen &, Window & );
8:
9: // ...
10:
11: };
12:
13: class Window
14:
15: {
16:
17: friend bool is_equal( Screen &, Window & );
18:
19: // ...
20:
21: };
作为一个类的函数又是另一个类的友元

如果我们决定该函数必须作为一个类的成员函数并又是另一个类的友元,则成员函数声明和友元声明如下:

1: class Window;
2:
3: class Screen
4:
5: {
6:
7: public:
8:
9: // copy 是类 Screen 的成员
10:
11: Screen& copy( Window & );
12:
13: // ...
14:
15: };
16:
17: class Window
18:
19: {
20:
21: // copy 是类 Window 的一个友元
22:
23: friend Screen& Screen::copy( Window & );
24:
25: // ...
26:
27: };
只有当一个类的定义已经被看到时它的成员函数才能被声明为另一个类的友元。这并不总是能够做到的。

例如如果Screen 类必须把Window 类的成员函数声明为友元,而Window类必须把Screen 类的成员函数声明为友元。该怎么办呢?在这种情况下可以把整个Window类声明为Screen 类的友元。

例如:



1: class Window;
2:
3: class Screen
4:
5: {
6:
7: friend class Window;
8:
9: // ...
10:
11: };
Screen 类的非公有成员现在可以被Window 的每个成员函数访问。

使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否
<think>嗯,用户问的是如何在中设置一个函数作为一个的友元。我需要先回忆一下C++中的友元机制。友元函数可以访问的私有成员,即使它不是该类成员函数。但这里的问题是要将一个成员函数设为一个的友元,而不仅仅是普通函数。 首先,我应该考虑正确的语法结构。假设有两个,A和B。要让B的某个成员函数成为A的友元,应该在A的定义声明该函数为友元。这时候,需要注意作用域的问题,因为友元声明需要明确指出该函数属于哪个。例如,在A中声明friend void B::func();,这样B的func函数就能访问A的私有成员了。 不过,这里有个前提条件,就是B必须在A之前被定义者至少被前向声明,否则编译器在A中声明友元时会不知道B的存在。但更复杂的是,如果B的成员函数要作为A的友元,那么该成员函数本身的声明必须在A的友元声明之前被看到。这可能涉及到A和B的相互依赖关系,需要仔细处理头文件的包含顺序和前置声明。 举个例子,可能需要先定义B,然后在A中声明友元函数者如果B的成员函数需要用到A,可能需要前置声明A,然后在B中声明函数,再在A中声明友元。这种情况下,可能需要调整定义顺序,使用前向声明来解决循环依赖的问题。 外,用户可能混淆了友元函数的不同情况。比如,普通友元函数一个成员函数作为友元的区别。需要明确说明,当友元是一个成员函数时,必须使用名加作用域解析运算符来限定函数名。 可能还需要提醒用户,友元关系是单向的,且破坏了封装性,应谨慎使用。例如,B的成员函数可以访问A的私有成员,但A的成员函数不能访问B的私有成员,除非在B中也进行相应的友元声明。 总结步骤应该是:1. 前向声明必要的;2. 定义B,并在其中声明成员函数(但可能实现放在后面,如果用到A的话);3. 定义A,并在其中声明B的成员函数为友元;4. 实现B的成员函数,此时可以访问A的私有成员。需要确保在声明友元时,B的成员函数已经被声明外,可能用户在实际应用中遇到了编译错误,比如“B::func()未声明“不完整的型”等,这时候正确的顺序和声明是关键。需要给出示例代码,展示正确的结构,可能还要处理头文件包含的问题,避免循环包含。 最后,应该提供一个具体的例子,让用户能够看到如何正确编写代码,并解释每一步的作用,以及需要注意的地方,比如访问权限、友元声明的正确语法、定义顺序等。</think>在 C++ 中,可以通过 **友元(friend)** 机制让一个成员函数访问一个的私有(`private`)保护(`protected`)成员。以下是具体实现方法: --- ### **核心步骤** 1. **前向声明**:若两个相互依赖,需先声明对方的存在。 2. **在目标声明友元函数**:在需要被访问的中,用 `friend` 关键字声明一个成员函数为友元。 --- ### **代码示例** ```cpp // 前向声明 ClassB,以便在 ClassA 中引用 class ClassB; class ClassA { private: int secret = 42; // 声明 ClassB 的成员函数为友元 friend void ClassB::accessSecret(ClassA& obj); }; class ClassB { public: void accessSecret(ClassA& obj) { // 可以访问 ClassA 的私有成员 std::cout << "Secret: " << obj.secret << std::endl; } }; ``` --- ### **关键细节** 1. **定义顺序**: - 若 `ClassB::accessSecret` 使用 `ClassA` 对象,必须先定义 `ClassA`。 - 但 `ClassA` 的友元声明需要 `ClassB` 的定义。此时需: 1. 前向声明 `ClassB`。 2. 定义 `ClassA` 并声明友元。 3. 定义 `ClassB` 的成员函数。 2. **修改后的正确顺序**: ```cpp // 前向声明 class ClassB; class ClassA { private: int secret = 42; // 声明友元(此时 ClassB 未完全定义,但成员函数需后续定义) friend void ClassB::accessSecret(ClassA& obj); }; class ClassB { public: void accessSecret(ClassA& obj); // 仅声明 }; // 成员函数定义(此时 ClassA 已完全定义) void ClassB::accessSecret(ClassA& obj) { std::cout << "Secret: " << obj.secret << std::endl; } ``` --- ### **注意事项** - **单向性**:友元关系是单向的。`ClassB` 可以访问 `ClassA`,反之不行(除非反向声明友元)。 - **谨慎使用**:友元破坏了封装性,应仅在必要时使用(如运算符重载紧密协作的)。 - **编译依赖**:若定义分散在多个头文件中,需注意包含顺序和循环依赖问题。 希望这能帮你理清思路!如果有进一步问题,欢迎追问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值