//student.h class Student { //...... }; //school.h #include "student.h" class School { //...... private: Student stu[50]; }; //main.cpp #include "student.h" #include "school.h" int main() { //...... return 0; }執行此專案讀者會發現,編譯器報“Student 型別重定義”錯誤。這是因為在 school.h 檔案中已經 #include 了一次 "student.h",而在 main.cpp 主程式又同時 #include 了 "school.h" 和 "student.h",即 Student 類的定義被引入了 2 次,C++不允許同一個類被重複定義。
#ifndef _NAME_H #define _NAME_H //標頭檔案內容 #endif其中,_NAME_H 是宏的名稱。需要注意的是,這裡設定的宏名必須是獨一無二的,不要和專案中其他宏的名稱相同。
#ifndef _STUDENT_H #define _STUDENT_H class Student { //...... }; #endif雖然該專案 main.cpp 檔案中仍 #include 了 2 次 "student.h",但鑑於 _STUDENT_H 宏只能定義一次,所以 Student 類也僅會定義一次。再次執行該專案會發現,其可以正常執行。
除此之外,#pragma once 只能作用於某個具體的檔案,而無法向 #ifndef 那樣僅作用於指定的一段程式碼。目前,幾乎所有常見的編譯器都支援 #pragma once 指令,甚至於 Visual Studio 2017 新建標頭檔案時就會自帶該指令。可以這麼說,在 C/C++ 中,#pragma once 是一個非標準但卻逐漸被很多編譯器支援的指令。
#pragma once class Student { //...... };再次執行專案,同樣可以正常執行。
當處理標頭檔案重複引入問題時,可以將如下語句新增到相應檔案的開頭:有關 _Pragma 操作符更多的功能和用法,本節不做詳細講解,這裡僅介紹如何用 _Pragma 操作符避免標頭檔案重複引入。
_Pragma("once")
比如,將該語句新增到前面專案中 student.h 檔案中的開頭位置,再次執行專案,其可以正常執行。事實上,無論是 C 語言還是 C++,為防止使用者重複引入系統庫檔案,幾乎所有庫檔案中都採用了以上 3 種結構中的一種,這也是為什麼重複引入系統庫檔案編譯器也不會報錯的原因。
另外在某些場景中,考慮到編譯效率和可移植性,#pragma once 和 #ifndef 經常被結合使用來避免標頭檔案被重複引入。比如說:除非對專案的編譯效率有嚴格的要求,強烈推薦讀者選用第一種解決方案,即採用 #ifndef / #define / #endif 組合解決標頭檔案被重複引入。
#pragma once #ifndef _STUDENT_H #define _STUDENT_H class Student { //...... }; #endif當編譯器可以識別 #pragma once 時,則整個檔案僅被編譯一次;反之,即便編譯器不識別 #pragma once 指令,此時仍有 #ifndef 在發揮作用。