invalid use of incomplete type和expected class-name before '{' token 問題分析

起源

如果你編寫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})

此時編譯通過(如果有更好的解決方案請留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章