編碼中發現一個奇怪的編譯錯誤,花了很長時間才找到問題所在。下面把重現這個問題的最精簡的代碼貼出來:/**//*
MyClass.h
存在一個namespace和一個類
*/
#ifndef _MY_CLASS_H_
#define _MY_CLASS_H_
namespace MySpace
...{
class MyClass
...{
public:
int Field;
};
}
#endif
下面的一個檔案聲明一個全域的指標,因為僅僅指示聲明,所以盡量不包含其他檔案:/**//*
global.h
聲明一個全域的指標
*/
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
class MyClass; //對存在的類型做一個聲明,不引入定義的標頭檔
extern MyClass* g_Obj;
#endif
下面的檔案使用全域變數和類型:/**//*
use.cpp
這個檔案裡面使用全域對象指標和類型
*/
#include "MyClass.h"
#include "global.h"
void test1()
...{
g_Obj = new MyClass();
g_Obj->Field = 1;
}
/**//*
g++ -o use.o -c use.cpp -g -Wall
*/
編譯use.cpp,產生了很多編譯錯誤:
only_use.cpp: In function `void test1()': only_use.cpp:11: error: invalid use of undefined type `struct MyClass' global.h:9: error: forward declaration of `struct MyClass' only_use.cpp:12: error: invalid use of undefined type `struct MyClass' global.h:9: error: forward declaration of `struct MyClass' |
你可能會說,得加上using namespace MySpace; 實際上,這句加進去還是編譯不過。當然,如果在global.h中包含MyClass.h,應該就能夠編譯過去了。但是我不想這麼做,對於一個指標類型,其類型只要聲明就好,不需要引入定義的。包含太多的標頭檔會引發編譯問題的。
試了很多辦法,最後發現,在use.cpp中的#include "MyClass.h"後加入一行:using MySpace::MyClass; 然後代碼就能夠編譯過去了。
總結一下:對於存在於namespace中的類型,如果在某個標頭檔中對型別宣告過,則在使用的時候要注意:
1、類型的定義檔案包含在前(#include "MyClass.h")
2、聲明namespace中的類型(using MySpace::MyClass;)
3、然後包含全域指標的聲明檔案(#include "global.h")
4、在其後使用就沒問題了