還是鄧俊輝老師資料結構中List那一章的例子。
List的周遊問題。
main.cpp裡調用
<code>PRINT ( La ); // La是一個自定義的List對象</code>
PRINT這個宏的定義就在main.cpp裡
<code>#define PRINT(x) { print(x); crc(x); checkOrder(x); }</code>
print的聲明在UniPrint/print.h裡
注意C++模闆類的定義和實作必須要在同一個檔案中,通常是頭檔案,因為編譯器要看到模闆實作才能展開模闆。
但是print.h裡的模闆類UniPrint隻有方法的聲明,沒有方法的實作。
是以print.h的末尾引入了print_implementation.h這個頭檔案。UniPrint::p的實作就在這個頭檔案裡。
這也是C++模闆類的常用寫法。
print_implementation.h裡又引入了Print_traversable.h,UniPrint::p的真正實作在Print_traversable.h裡。(windows上C++頭檔案不分大小寫)
print_traversable.h
運作到<code>s.traverse( print );</code>這一句的時候會跳到traverse方法裡去。
list.h
從traverse方法來看,它接收的是一個函數指針,這個函數接收一個T型引用的參數,且沒傳回值。
是以s.traverse ( print );中print方法也應該接收一個T型引用的參數。
縱觀print.h中隻有這一句符合條件:<code>template <typename T> static void print ( T& x ) { UniPrint::p ( x ); }</code>
咦?不對呀,這怎麼又回來了?怕不是死循環?
是的,這個地方卡了我好久。後來我想通了。PRINT裡調用print的時候,會先走到print_traversable.h裡去執行UniPrint::p的實作,
執行到s.traverse(print);這一句後,是在traverse這個方法裡調用print的。這個時候UniPrint::p和traverse裡的T已經被替換成int類型了。
也就是模闆已經被執行個體化了。是以debug的時候發現,雖然程式又走到了
print.h中的這一句:<code>template <typename T> static void print ( T& x ) { UniPrint::p ( x ); }</code>
但不會再次走到print_traversable.h裡,因為T已經被替換了。 此時程式會找 <code>void print(int& x){UniPrint::p(x);}</code>的實作,
也就是這裡:
print_basic.cpp
<code>void UniPrint::p ( int e ) { printf ( " %04d", e ); }</code>
C++中沒有print函數。這個print是自己定義的喲。
搞清楚了這個, <code>#define PRINT(x) { print(x); crc(x); checkOrder(x); }</code>裡crc(x)就好了解了。幾乎是同樣的道理。
crc_list
crc_Elem.h
所謂函數對象就是定義了調用操作符()的類對象。當用該對象調用此操作符時,其表現形式如同普通函數調用一般,是以取名叫函數對象
與print不同的地方在于這裡調用的是traverse的另一個版本:
List_traverse.h
看,visit加一個圓括号,就是在用Crc重載後的運算符()。
對了,這個int什麼時候傳進去的?
在調用PRINT宏之前,在main函數這裡傳進去的:
<code>testList<int> ( atoi ( argv[1] ) );</code>
testList也是一個模闆方法: