C/C++ 包含顺序引发的错误一例


这个错误是我最近在写一个Qt小程序的时候出现的,觉得有一定价值,打算写出来。由于我水平实在太弱,故若高手们看了之后觉得浪费了自己的生命,还请轻拍。

假如我的程序除了main.cpp之外还有3个.h/.cpp组,这里用A.h、B.h、C.h代替:

// main.c
#include "A.h";
// Do something...
return 0;
// A.h
#ifndef A_H
#define A_H

#include "B.h";
#include "C.h";

#endif
// B.h
#ifndef B_H
#define B_H

class A_Class;

#endif
// C.h
#ifndef C_H
#define C_H

#include "A.h";
void a_function(A_Class an_arg);

#endif

可以看出,C.h的一个函数中要用到B.h中声明的一个叫做A_Class的类。由于A.h包含了C.h和B.h,而C.h又包含了A.h,因此看上去C.h可以通过A.h包含B.h,从而用上B.h中声明的类。

之后通过qmake等等自动写makefile的工具生成makefile,进行编译。然而在编译的时候,编译器却会给出错误,说A_Class没有被声明。而如果把A.h中包含的顺序调换一下,先包含B.h,再包含C.h,编译就能够通过。

问题主要就出在A.h和C.h的相互包含上。A.h先包含了C.h,根据生成的makefile,编译器会先开始处理C.h,而在C.h被处理完毕之前,B.h是不会被处理的,因此编译器会说找不到B.h中声明过的类。而如果把A.h中包含的顺序调换,在处理C.h之前,B.h已经被处理好了,就不会出现找不到声明的情况。

因此为了避免这类问题,最好把头文件间的关系理清,不要出现这种“互相包含”的情况。如果非要用到彼此的东西,可以使用前向声明(但这种方法实际操作起来是很麻烦的)。另外,既然有了#ifndef的保护,凡是要用到的东西统统在头文件里包含一遍,这样也可以确保所有需要用到的东西在用到之前都是准备好的。

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s