C++头文件相互包含的问题

return_zero 2011-09-13 09:59:52

昨天发的一个帖子:http://topic.csdn.net/u/20110912/16/6b625bc9-0b85-421e-bde2-01bc5f7cbf76.html
(暂时还存在问题,仍未结贴)

下面叙述详细的问题:

遇到这样一个情况,下面是一个简化的说明:

在A.h中定义了一个类模版,并且在A.h中需要#include "B.h"(即,需要知道B的定义)
而在B.h中又使用了A.h中定义的模版,因此也需要#include "A.h"(即,又需要知道A的定义)

问题1:这段代码应该是不对的,但在gcc3.3.4上没有报错,而在gcc4.1.2上报错:
error: incomplete type 'CXXX' used in nested name specifier

问题2:通常相互依赖的2个类,把有依赖项的函数的具体实现都放入CPP中,类似的问题就解决了。但是A.h中使用的是类模版,大部分编译器只支持 inclusion compliation model,即,不支持分别编译模型。所以,将依赖的代码放在CPP中就不可行了。


有些理解不对的地方,请大大们指教!分数不多,见谅

...全文
2229 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
stendson 2011-09-14
  • 打赏
  • 举报
回复
另外给你推荐一本书 c++ template
http://www.docin.com/p-92736755.html
第六章 好好看吧
stendson 2011-09-14
  • 打赏
  • 举报
回复
前置声明 class T;只是告知编译器 存在这个类型 主要是用于模板 显示实例化
template class TemplateClass<T>;
只要将这句加到T的.h中就行了 但是这样就只能实例化T 不能实例化其他类型
menzi11 2011-09-14
  • 打赏
  • 举报
回复
#ifndef AAAAA
#define AAAAA

#include "B.h"

class A{...};


#endif


return_zero 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 qq120848369 的回复:]

你昨天可没说那是个模板类。
[/Quote]
感谢 蜡笔小新 qq120848369的关注!
不知道当初设计者的意图是什么,类之间耦合的比较厉害,而且奇怪为什么gcc 3.3.4没有报错。
PS:第一个帖子还有一个问题没有回答。
qq120848369 2011-09-13
  • 打赏
  • 举报
回复
你昨天可没说那是个模板类。
return_zero 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 dahuaixiaohuai 的回复:]

模板不支持分离编译,所以模板没有CPP文件一说。
[/Quote]
A.h中定义的模版类和实现,A.cpp中是另外一些类的实现,见16L
return_zero 2011-09-13
  • 打赏
  • 举报
回复
谢谢,可能是我没有说清楚,我是在维护编译的代码,现在出现了这样的问题(见顶端问题1)。

我现在把问题再描述一下:

// A.h
#include "B.h"// 要知道B的定义

template <...>// A.h 中的模版类 CA
class CA
{
public:
void funA()
{
B:funB();// 这里需要知道 B 的完整定义
}

};

// B.h
#include "A.h"// 要包含模版类的定义
class B
{
typedef CA<...> CAlias;// 这里需要使用模版类 CA
CAlias * m_b;

//...

static funB();
};


相互依赖的问题就出现了。

[Quote=引用 17 楼 luciferisnotsatan 的回复:]

#ifndef _A_H_
#define _A_H_



class A
{
public:
static A& getTheApp();
void funA();

private:
static A* theApp;


};
#include "B.h"
#endif

这样,你就可以把funB放到B.h里去……
[/Quote]
一叶之舟 2011-09-13
  • 打赏
  • 举报
回复
模板不支持分离编译,所以模板没有CPP文件一说。
坏男孩 2011-09-13
  • 打赏
  • 举报
回复
ifndef
define
endif
5t4rk 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 luciferisnotsatan 的回复:]
引用 11 楼 return_zero 的回复:

引用 9 楼 luciferisnotsatan 的回复:

把void funB()的实现放到b.cpp里去。

我试过,问题是别的类在使用模版类的时候怎么办,如果#include "B.cpp",可能会出现重复inclusion问题(重复定义问题)。

A.h里没用到B.h的内容。
把#include "B.h"的代码放到A……
[/Quote]
++
luciferisnotsatan 2011-09-13
  • 打赏
  • 举报
回复
#ifndef _A_H_
#define _A_H_



class A
{
public:
static A& getTheApp();
void funA();

private:
static A* theApp;


};
#include "B.h"
#endif

这样,你就可以把funB放到B.h里去了。
但如果这是都是自己写的代码,建议还是自己整理下思路。看看能不能简化,别做出这么复杂的东西。
return_zero 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 luciferisnotsatan 的回复:]

如果是模版,就把A.cpp里的实现全写到A.h里。把A.cpp删了。
[/Quote]
目前就是这样的,模版类是在A.h中定义和实现的,A.cpp中实现了一些其他的函数(说明一下,A.h中除了定义了一个模版类之外,还定义了几个普通的类)。

如果将A.cpp删除,本质上还是没有解决头文件 circular inclusion 的问题,即两个相互依赖的类相互包含的问题。

鄙人写了一个测试的例子:非模版的两个相互包含的类,可以通过把依赖的实现代码移到CPP中得以解决,但是,对于含有模版的两个相互包含的类,就无可奈何了。

下面的代码是——不含模版类时的解决方法:

// A.h
#ifndef _A_H_
#define _A_H_

#include "B.h"

class A
{
public:
static A& getTheApp();
void funA();

private:
static A* theApp;


};
#endif

/////////////////////////////////////////////
// A.cpp

#include "stdafx.h"
#include "A.h"


A* A::theApp = NULL;

A& A::getTheApp()
{
if (theApp == NULL) {
theApp = new A();
}

return *theApp;
}

void A::funA() {
printf("funA...\n");

B b;
printf("i_b = %d\n", b.i_b);
}
////////////////////////////////////////////////

// B.h
#ifndef _B_H_
#define _B_H_

#include "A.h"

class B
{
public:
B(){i_b = 100;}
void funB();
int i_b;

};
#endif

/////////////////////////////////////

// B.cpp

#include "stdafx.h"
#include "B.h"

void B::funB()
{
printf("funB...\n");
A::getTheApp().funA();
}

//////////////////////////////

// 主程序

#include "stdafx.h"
#include "A.h"
#include "B.h"


int main(int argc, _TCHAR* argv[])
{
B b;
b.funB();

return 0;
}


return_zero 2011-09-13
  • 打赏
  • 举报
回复
@luciferisnotsatan 12L 谢谢
您说的“A.h里没用到B.h的内容”,鄙人不太理解。
在A.h中必须要知道B.h的定义,只有前向声明是不行的。
比如,在A.h中,调用
B::static_funB();// 在A.h中调用B.h中的静态函数,此时在A.h中必须要知道B类型的完整定义。


冼鸿文 2011-09-13
  • 打赏
  • 举报
回复
我习惯把他们都放在同一个文件上,前置声明一下就行了
luciferisnotsatan 2011-09-13
  • 打赏
  • 举报
回复
如果是模版,就把A.cpp里的实现全写到A.h里。把A.cpp删了。
luciferisnotsatan 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 return_zero 的回复:]

引用 9 楼 luciferisnotsatan 的回复:

把void funB()的实现放到b.cpp里去。

我试过,问题是别的类在使用模版类的时候怎么办,如果#include "B.cpp",可能会出现重复inclusion问题(重复定义问题)。
[/Quote]
A.h里没用到B.h的内容。
把#include "B.h"的代码放到A.h最后(#endif上面)。
return_zero 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 luciferisnotsatan 的回复:]

把void funB()的实现放到b.cpp里去。
[/Quote]
我试过,问题是别的类在使用模版类的时候怎么办,如果#include "B.cpp",可能会出现重复inclusion问题(重复定义问题)。
return_zero 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 healer_kx 的回复:]

引用 2 楼 jackyjkchen 的回复:

1.相互引用不能用对象,只能用引用和指针

2.大部分编译器不支持分离编译


++

补充一下,解决起来,可以利用CPP文件,就是.h里面只有声明(互相引用的就只用指针引用形式,这样就不需要include了,只要前置声明一下。在cpp里面再include即可)

模板永远不会支持export关键字了。
[/Quote]
或者说,您提出的解决方法,如何解决问题2呢?即,头文件A.h中定义的是类模版。
luciferisnotsatan 2011-09-13
  • 打赏
  • 举报
回复
把void funB()的实现放到b.cpp里去。
ningto.com 2011-09-13
  • 打赏
  • 举报
回复
模板的话不支持分开编译,
要把头文件源文件一起包含,如:
#include "test.h"
#include "test.cpp"
加载更多回复(18)

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧