1、#ifndef #define #endif標頭檔保護符
在編譯的過程中,每一個.cpp檔案被看成一個單獨的檔案來編譯成單獨的編譯單元,#ifndef 保證類的標頭檔在同一個.cpp檔案中被多次引用後不會出現重定義問題。
注意:只是防止在同一個.cpp檔案中被多次引用。
例子:
// file1.hclass file1{};// file2.h#include "file1.h"class file2{};// file3.h#include "file1.h"#include "file2.h"
file3.h展開來是這樣的:
// file1.h展開的內容class file1{};// file2.h展開的內容class file1{};class file2{};
這時候就會出現重定義了,如果在每個檔案加上#ifndef標頭檔保護符:
// file1.h#ifndef _FILE1_H_#define _FILE1_H_class file1{};#endif // !_FILE1_H_
// file2.h#ifndef _FILE2_H_#define _FILE2_H_#include "file1.h"class file2{};#endif // !_FILE2_H_
// file3.h#ifndef _FILE3_H_#define _FILE3_H_#include "file1.h"#include "file2.h"#endif // !_FILE3_H_
這時候展開file3.h時,因為_FILE1_H_只會被定義一次,所以就不會出現重定義錯誤。
2、變數的聲明和定義
定義:用於為變數分配儲存空間,還可以為變數指定初始值。在一個程式中,變數有且僅有一個定義。
聲明:用於向程式表明變數的類型和名字。在一個程式中,聲明可以有多個。定義也是聲明:當定義變數時我們聲明了它的類型和名字。可以通過使用extern關鍵字聲明變數名而不定義它:extern int i;。 例子:
// file1.h#ifndef _FILE1_H_#define _FILE1_H_int a = 1;#endif // !_FILE1_H_
// file2.h#ifndef _FILE2_H_#define _FILE2_H_#include "file1.h"#endif // !_FILE2_H_
// main.cpp#include <iostream>int main(){extern int a;std::cout << a << std::endl;system("pause");return 0;}
這時候編譯會報錯,因為在file1.h定義了a,在file2.h的展開中又定義了a。
有人會問,#ifndef不是防止重定義的嗎。#ifndef是防止在同一個檔案的重定義,在上面的情況,file1.h和file2.h是兩個不同的檔案,所以會在file1.h和file2.h同時出現int a = 1,就出現重定義錯誤了。
所以不要在標頭檔定義變數,最好的做法是:在標頭檔聲明變數,在.cpp定義變數,在需要使用該變數的地方先聲明再使用。
修改下上面的例子:
// file1.h#ifndef _FILE1_H_#define _FILE1_H_extern int a;#endif // !_FILE1_H_
// file1.cpp#include "file1.h"int a = 1;
// file2.h#ifndef _FILE2_H_#define _FILE2_H_#include "file1.h"#endif // !_FILE2_H_
main.cpp不變,這時候就可以正常運行了。
3、可以在標頭檔定義的三個例外
(1)類的定義。
類的定義更多像是聲明,因為此時並沒有分配空間。
(2)值在編譯時間就已知的const對象。
如:const char c = 'c';,這個是在編譯時間就已經確定值的,之後程式不能改變。
而const char *c = 'c';是不可以的,因為指標不是在編譯時間確定值的。
(3)inline內嵌函式。