c++中友元函数带来的头文件的互包含问题 |
您所在的位置:网站首页 › c加加的万能头文件怎么写 › c++中友元函数带来的头文件的互包含问题 |
关于头文件的一点使用感悟
模块化。这没啥好说的,一个类一个头文件,然后在各自的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&); }; #endifB.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 |