c++中友元函数带来的头文件的互包含问题

您所在的位置:网站首页 c加加的万能头文件怎么写 c++中友元函数带来的头文件的互包含问题

c++中友元函数带来的头文件的互包含问题

2024-05-27 11:00| 来源: 网络整理| 查看: 265

关于头文件的一点使用感悟

模块化。这没啥好说的,一个类一个头文件,然后在各自的cpp文件中定义。

当模块化的类之间有交互关系的时候,利用合理的头文件声明可以让你的模块代码能够写下去。

如果用到了一个类的具体内容,那么应该包含这个类所在的头文件,只有这样才能知道这个类的具体定义,从而能够编译出相应内容。

如果只用到了一个类的名字,而没有用到实际内容,则只需要给出这个类的申明即 class A 即可,不用包含头文件了。

提出问题 如何构造头文件来体现以下关系: A类,B类。 A类中有一个私有变量。 B类中的fun函数是A类中的友元函数。 可以通过fun这个友元函数来改变A的对象的私有变量值。 要求:B的所有实现放在B.cpp中 A的所有实现放在A.cpp中 从而实现模块化。 网上对这个问题的大多数分析都是从编译的顺序来说的 这是没错的,但这里说的是自己总结的一个小技巧。 直接给出解决办法

以下内容省略了ifndef…define…endif

A的头文件

/************************************************************/ #include"B.h" //因为在类A中声明了B中的一个函数 //而只有B已经定义了才能知道B中有什么 //所以需要包含B类所在的头文件 //这一点理解非常重要 //因为它涉及到了类的内容的使用,不单单是声明 class A{ friend void B::fun(A&); public: A(int i):a(i){} int getA(){return a;} private: int a; };

B的头文件

/**********************************************************/ //B.h文件 class A; //因为在这里只涉及到了A类的声明 //而没有涉及到A类的内容的使用 //所以只需要申明有A这个类型就可以了 class B{ public: void fun(A&); }

B的cpp文件

/*********************************************************/ //B的函数一般思想是在B.cpp中实现 //B.cpp #include"B.h" //这里是基础的必须有的内容 #include"A.h" //这里是因为用到A中的内容了,并且在这里需要得到fun函数是 //A的友元这一含义,所以说包含这个头文件是必须的 void B::fun(A& aa){ aa.num = 9999; //在B类的函数中修改A中的私有成员 }

main.cpp(运行主程序)

#include #include"B.h" #include"A.h" int main(){ A a(10); B b; b.fun(a); cout private: int x; public: B(int); void fun(A&); }; #endif

B.cpp

#include "B.h" B::B(int a) { x = a; } void B::fun(A& aa) { aa.num = 9999; }

main.cpp

#include #include"A.h" #include"B.h" using namespace std; int main() { B b(10); A a(5); b.fun(a); cout >使得替换目标向A.h转变。 经过A.h中的#ifndefine…#define…#endif,编译器已经定义了和A.h有关的头文件标识!!

我们看A.h

#include"B.h" class A { friend void B::fun(A&); private: int num; public: A(int); int getNum(); };

发现了A.h的第一句是 #include"B.h" ,则应该先把这部分替换到A.h文件中,再把整个A.h文件中的声明信息替换到main中。

既然上面要先替换B.h则我们转到B.h进行同样的查看,看是否有包含更深的头文件包含,B.h内容如下:: #ifndefine #define _B_H_ #include"A.h" class B { private: int x; public: B(int); void fun(A&); }; #endif

发现了B.h第一句是 #include"A.h" ,因为我们本意是希望B中声明的fun的参数有意义。但是但是但是!!!! 由于在第一步main.cpp中我们先找到的是 #include"A.h",经过了A.h中的已经定义过的头文件标识,这里的 #include"A.h"不会再生效了,因此实际上包含的是除了**#include"A.h"**之外的B的头文件中的内容。

这时候main.cpp经过替换后的内容结构如下:

iostream.h 部分的声明(我们不关心) B.h中的声明部分 class B { private: int x; public: B(int); void fun(A&); }; A.h中除了 #include"B.h" 的其余内容(因为这一个头文件已经被替换成上面的B.h中的内容) class A { friend void B::fun(A&); private: int num; public: A(int); int getNum(); };

开始编译,则会报出B类中A是错误的语法标识。原因是类A在之前并没有被定义或者引用申明。 并且由于这个**#include"A.h"**没被替换,所以在B.cpp中的实现也会有问题:

#include "B.h" B::B(int a) { x = a; } void B::fun(A& aa) { aa.num = 9999; ///由于没有A.h,所以不可访问 }

再说一句,根据大量的实验表明,如果你的A,B头文件是互相包含关系,那么,即便你在B中申明Class A;也不顶事,编译器会报错说你A类中定义友元friend void B::fun(A&) 的B 不是标识符也不是命名空间!!!

一句话,用到内容再包含头文件,用不到内容就只申明class。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3