起源
如果你編寫c++代碼喜歡把實現和聲明寫在一塊的話,可能會出現這個編譯錯誤。意思就是你使用了不完整的類型(儘管你有前置聲明)
例如下面這份代碼
class A;
class Base {
public:
// invalid use of incomplete type 'class A'
A func(){
return A();
}
};
class A { };
class A; 只是告訴編譯器有A這個類,而後面使用了 A() ,由於編譯器還沒編譯到類A的所有代碼,因此不知道A究竟有沒有 A() 這個構造函數。
解決方法:
在class A 定義後面在去實現func函數
class Base {
public:
// fix error
A func();
};
class A { };
A Base::func() {
return A();
更多的問題
問題:有兩個類Base,A;類A繼承了類Base,類Base中某個函數返回值或者參數使用到了類A。
爲了簡化問題,假定有如下場景(請使用vs或者cmake來編譯多個文件,以下我使用cmake來編譯)
本例子中我的 CMakeLists.txt 如下(不會用CMake請使用vs)
cmake_minimum_required(VERSION 3.12)
project(untitled)
set(CMAKE_CXX_STANDARD 14)
add_executable(untitled main.cpp Base.cpp)
target_link_libraries(${PROJECT_NAME})
-
例子1
嘗試使用3個文件Base.h A.h main.cpp 來實現Base.h 文件內容如下
#ifndef BASE_H #define BASE_H #include "A.h" class Base { public: A func() { return A(); } }; #endif // BASE_H
A.h 文件內容如下
#ifndef A_H #define A_H #include "Base.h" class A:public Base { }; #endif // A_H
main.cpp 內容如下
#include "Base.h" #include "A.h" int main() { Base().func(); }
編譯之後(gcc)出現錯誤:
expected class-name before '{' token
(位於A.h處)
意思是沒有Base這個類(因爲Base這個類還沒識別到,所以需要一個前置聲明) -
例子2(修復expected class-name before ‘{’ token)
在上面的基礎上修改 A.h 如下#ifndef A_H #define A_H #include "Base.h" class Base; class A:public Base { }; #endif // A_H
再次編譯,發現出現新的錯誤
invalid use of incomplete type class 'Base'
(位於A.h文件處)你在這3個文件中多次改來改去,發現總是有
invalid use of incomplete type
或者expected class-name before '{' token
這2個錯誤,怎麼改都沒辦法編譯通過。經過研究後,我發現了正確的做法。
問題解法
你必須引入一個新的cpp文件纔可以解決上面的問題,這個文件可以命名爲Base.cpp ,此時有4個文件 Base.h, Base.cpp ,A.h, main.cpp (如果需要的話可以加入A.cpp)
關鍵點:
Base.h的寫法(基類不要include 派生類,需要用到派生類的話直接前置聲明,函數參數或者返回值有用到派生類的話,一定要把函數的聲明和實現分開來寫)
#ifndef BASE_H
#define BASE_H
class A;
class Base {
public:
A func();
};
#endif // BASE_H
Base.cpp寫法
#include "Base.h"
#include "A.h"
A Base::func() {
return A();
}
A.h寫法
#ifndef A_H
#define A_H
#include "Base.h"
class Base;
class A: public Base { };
#endif //A_H
main.cpp
#include "Base.h"
#include "A.h"
int main() {
Base().func();
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(untitled)
set(CMAKE_CXX_STANDARD 14)
add_executable(untitled main.cpp Base.cpp)
target_link_libraries(${PROJECT_NAME})
此時編譯通過(如果有更好的解決方案請留言)