#include和前置聲明(forward declaration)
1. 當不需要調用類的實現時,包括constructor,copy constructor,assignment operator,member function,甚至是address-of operator時,就不用#include,只要forward declaration就可以了。
2. 當要用到類的上面那些“方法”時,就要#include
例子:
boy.h
#ifndef __BOY__H_
#define __BOY__H_
#include<string>
using namespace std;
class Boy {
private:
string name;
int age;
};
#endif
test1.h
#include<iostream>
class Boy;
class People {
Boy getBoyInfo();
};
test2.h
#include<iostream>
#include "boy.h"
class Boy;
class People {
Boy getBoyInfo();
};
一個采用前置聲明,一個采用#include "boy.h"加入了Boy的定義。兩種方法都能通過編譯。但是test1.h 這種寫法更好。如果boy.h 的private成員變量改變,比如變成 char *name; test1.h 不需要重新編譯,而test2.h 就要重新編譯,更糟的是如果test2.h 還與其他很多頭文件有依賴關系,就會引發一連串的重新編譯,花費極大的時間。可是事實上改變一下寫法就可以省去很多功夫。所以能用前置聲明代替#include 的時候,盡量用前置聲明
有些情況不能用前置聲明代替#include
比如test1.h改成
#include<iostream>
using namespace std;
class Boy;
class People {
public:
Boy boy;
};
test.cpp:7:9: error: field ‘boy’ has incomplete type
Boy boy;
^
會編譯錯誤,因為Boy boy定義了一個Boy類型變量,編譯器為boy分配內存空間的時候必須知道boy的大小,必須包含定義Boy類的boy.h文件。
這是可以采用指針來代替
#include<iostream>
using namespace std;
class Boy;
class People {
public:
Boy *boy;
};
指針的大小是固定的。在32位機上是4字節,64位機上是8字節。這時編譯Task1的時候不需要Boy的大小,所以和Boy的定義無關。
如果使用object reference 或 object point 可以完成任務,就不要用object
這樣可以盡最大可能避免#include
為聲明式和定義是提供不同的頭文件
第一個原則應該是,如果可以不包含頭文件,那就不要包含了。這時候前置聲明可以解決問題。如果使用的僅僅是一個類的指針,沒有使用這個類的具體對象(非指針),也沒有訪問到類的具體成員,那么前置聲明就可以了。因為指針這一數據類型的大小是特定的,編譯器可以獲知。
第二個原則應該是,盡量在CPP文件中包含頭文件,而非在頭文件中。假設類A的一個成員是是一個指向類B的指針,在類A的頭文件中使用了類B的前置聲明並編譯成功,那么在A的實現中我們需要訪問B的具體成員,因此需要包含頭文件,那么我們應該在類A的實現部分(CPP文件)包含類B的頭文件而非在聲明部分(H文件)包含。