• 为什么 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了  其实是看的别人的博客!

  • 相关阅读:
    Python logging根据时间创建日志文件
    ORACLE Merge into 使用
    go安装goctl
    Oracle 行转列
    ORACLE with as查询优化
    Linux环境使用Docker安装MongoDb
    Linux环境使用Docker安装MySql
    Docker基础操作
    Linux基础命令
    Ansible自动化运维介绍
  • 原文地址:https://www.cnblogs.com/zhangkele/p/7628141.html
Copyright © 2020-2023  润新知