為什麽 c++中函數模板和類模板的 聲明與定義需要放到一起?
阿新 • • 發佈:2017-10-05
color code 我們 ack 二進制 通過 如果 之前 類型
將模板的聲明與定義寫在一起實在很不優雅。嘗試用“傳統”方法,及在.h文件裏聲明,在.cpp文件裏定義,
然後在main函數裏包含.h頭文件,這樣會報鏈接錯誤。why!!!!!!!!!!!!!
這是因為函數模板要被實例化後才能成為真正的函數,在使用函數模板的源文件中包含函數模板的頭文件,
如果該頭文件中只有聲明,沒有定義,那編譯器無法實例化該模板,最終導致鏈接錯誤。(類模板同樣!!)
1 //---------------test.h-------------------// 2 void f();//這裏聲明一個函數f 3 //---------------test.cpp--------------// 4 #include”test.h” 5 void f() 6 { 7 …//do something 8 } //這裏實現出test.h中聲明的f函數 9 //---------------main.cpp--------------// 10 #include”test.h” 11 int main() 12 { 13 f(); //調用f 14 }
編譯時會生成兩個obj文件,main.obj和test.obj,而在main.obj裏並沒有f函數的二進制代碼,這些代碼實際存在於test.obj中。在main.obj中對f的調用只會生成一行call指令,call指令的地址由鏈接器生成。
1 //-------------test.h----------------// 2 template<class T> 3 class A 4 { 5 public: 6 void f(); //這裏只是個聲明 7 }; 8 //---------------test.cpp-------------// 9 #include”test.h” 10 template<class T> 11 void A<T>::f() 12 { 13 …//do something 14 } 15 //---------------main.cpp---------------// 16 #include”test.h” 17 int main() 18 { 19 A<int> a; 20 a. f(); 21 }
我們知道模板有個具現化的過程,在未被使用的時候是不會生成二進制文件的。所以當鏈接器去找f函數的地址時,因為在這之前沒有調用過f(),test.obj裏自然就沒有f函數的二進制代碼,於是就會報錯。
要使模板聲明與定義分開也不是沒有辦法。
第一種辦法是在main函數裏包含cpp文件
1 //-------------test.h----------------// 2 template<class T> 3 class A 4 { 5 public: 6 void f(); //這裏只是個聲明 7 }; 8 //---------------test.cpp-------------// 9 #include”test.h” 10 template<class T> 11 void A<T>::f() 12 { 13 …//do something 14 } 15 //---------------main.cpp---------------// 16 #include”test.cpp” //careful!!!!!!!!! 17 int main() 18 { 19 A<int> a; 20 a. f(); 21 }
這樣三個文件的內容通過include實際上包含在同一個文件裏,自然就不會出錯了
1 //-------------test.h----------------// 2 template<class T> 3 class A 4 { 5 public: 6 void f(); //這裏只是個聲明 7 }; 8 #include<test_impl.h>
9 //---------------test_impl.h-------------// 10 template<class T> 11 void A<T>::f() 12 { 13 …//do something 14 }
15 //---------------main.cpp---------------// 16 #include”test.h” 17 int main() 18 { 19 A<int> a; 20 a. f(); 21 }
這兩種方法實際上都是包含編譯,沒有本質的區別,不過感覺第二種方法看起來比較舒服
1 //-------------test.h----------------// 2 template<class T> 3 class A 4 { 5 public: 6 void f(); //這裏只是個聲明 7 }; 8 //---------------test.cpp-------------// 9 #include”test.h” 10 template<class T> 11 void A<T>::f() 12 { 13 …//do something 14 } 15 template class A<int>;//!!!!!!!!!!在這裏實現了具現了類型 這樣編譯就不會有問題了 但是這樣不太好 自己想為什麽 !!! 16 //---------------main.cpp---------------// 17 #include”test.h” 18 int main() 19 { 20 A<int> a; 21 a. f(); 22 }
差不多了吧 就這樣OK了 其實是看的別人的博客!
為什麽 c++中函數模板和類模板的 聲明與定義需要放到一起?