為什么 c++中函數模板和類模板的 聲明與定義需要放到一起?


將模板的聲明與定義寫在一起實在很不優雅。嘗試用“傳統”方法,及在.h文件里聲明,在.cpp文件里定義,

然后在main函數里包含.h頭文件,這樣會報鏈接錯誤。why!!!!!!!!!!!!!

這是因為函數模板要被實例化后才能成為真正的函數,在使用函數模板的源文件中包含函數模板的頭文件,(carefully!!!)

如果該頭文件中只有聲明,沒有定義,那編譯器無法實例化該模板,最終導致鏈接錯誤。(類模板同樣!!)

 

 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了  其實是看的別人的博客!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM