大型開發都會遇到的問題
隨着軟件規模的擴大,包含在一個工程中的模塊的數量在不斷增長,模塊之間的依賴關係也日益複雜。這裏只舉一個相對簡單的例子:一個包含2個類,5個文件的工程。
ImportantClass.h
頭文件中聲明瞭構造函數,doWork成員函數和數據成員buffer。
ImportantClass.cpp
cpp文件中爲構造函數和doWork提供了最簡單的實現。
userclass.h
聲明瞭構造函數,析構函數和doSomething成員函數以及ImportClass類型的數據成員。由於ip是ImportClass的實例,所以構建UserClass的聲明中需要ImportantClass頭文件(包含類結構信息)。
userclass.cpp
userclass.cpp爲構造函數,析構函數和doSomething成員函數提供了最簡單的實現。
main.cpp
代碼中創建了一個UserClass對象並調用了它的doSomething成員函數。
爲了理解上述代碼中的問題,首先明確一件事:一般來講C++編譯器編譯的編譯對象是工程中的那些cpp文件。.h文件一邊不會單獨編譯,而是和包含它的cpp文件一起編譯。具體到例子工程,可以大致如下理解:
importclass.cpp在編譯時同時編譯了importclass.h文件。
userclass.cpp在編譯時同時編譯的userclass.h文件和importclass.h文件。
main.cpp在編譯時同時編譯了userclass.h和importclass.h文件。
上面代碼中的主要問題是main.cpp真正希望使用的是UserClass,但由於userclass.h又引用了importantclass.h,所以產生了額外的依賴關係。
除了main.cpp以外,importclass.cpp和userclass.cpp中實際會使用到ImportClass類,這兩處依賴關係是必要的。
前置聲明
上述問題的解決方法就是前置聲明,具體代碼如下。
代 碼中的變化有兩點,一個是數據ImportantClass成員的類型變成了指針類型;另一個是include語句變成了class聲明語句。兩個變化缺 一不可,第二個變化是第一個變化的前提條件。因爲這裏只是聲明瞭指針類型,所以只要告訴編譯器ImportantClass一個類就夠了。真正的類型信息 在userclass.cpp中提供。這種方式就是前置聲明。以下是修改過的userclass.cpp文件:
通過這種方式消除了main.cpp對於ImportantClass的依賴。項目的依賴層次越多,前置聲明的效果也就越明顯。
enum前置聲明
C++11中,enum類型也可以前置聲明瞭。下面直接引用C++ Primer中的例子。
enum intValues : unsigned long long; //不限定作用域的,必須指明類型
enum class open_modes; //限定作用域的也可以指定,如果不指定則默認int
實際的枚舉值可以在另外的cpp文件中另外定義。