1. 程式人生 > >為什麽 c++中函數模板和類模板的 聲明與定義需要放到一起?

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

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++中函數模板和類模板的 聲明與定義需要放到一起?