最近在做项目的时候用到了模板类

果不其然出现了那个错误

LNK2019:无法解析的外部符号

网上百度到的结果繁花怒放,大多数不符合我的需求,故自己研究了下C++的模板类规则,试图找出问题所在

————————————下面是解决方法——————————————

首先将出现这个错误应该怎么处理的方法写出来,解一些急着知道结果的攻城狮们燃眉之急:

1.在主函数包含头文件时将实现模板类的函数也包含进来,如模板类在function1.cpp中实现,则在主函数中添加 #include                 "function.cpp"

2.将模板类的实现方法写在头文件里面,如模板类的头文件为:function1.h,那么就把实现要用到模板类的函数实现方法写在这     里

3.在实现模板类的文件中调用一下模板类

——————————————下面是详解———————————————

以下解析皆以一个模板类的文件:function1.h 和 function.cpp  ,以及一个主函数文件:main.cpp  说明。

首先需要了解的是,一个项目文件从代码段到最终变成可以执行的.exe文件是经过了:替换—编译—连接—生成 这四个步骤的,想要了解具体的编译过程可以参照我以前写过的一篇文章:【c语言】从高级语言到可以执行的EXE程序的编译过程。在编译器中,一个编译单元(.obj文件)是由一个.cpp文件以及该头文件所 include 的头文件所组成.

如本篇文章中 function1.cpp 的代码如下:

#include "function.h"
#include <iostream>void test()
{//do anything~
}

function.h的代码如下:

#ifndef _FUNCTION_H_
#define _FUNCTION_H_void test();#endif

main.cpp的代码如下:

#include "fuction.h"void main()
{test();
}

那么在该项目中存在两个编译单元:

当一个项目中的所有编译单元(.obj文件)都已分离的形式独自进行编译之后,再由连接器将各个单独的编译单元进行连接,从而成为一个可以执行的.exe文件。那么,连接器是如何进行编译单元连接的呢?在C++ 的描述里,程序在编译的过程中会生成三个表:重定向表,导出符号表以及未解决符号表,而其中的导出符号表的作用是将程序中的所有符号与实际的地址联系在一起,而连接器要做的就是通过查找导出符号表中符号的实际地址将各个单独编译单元连接在一起,以本章项目为例:

在main.cpp这个编译单元里面调用了函数 test() , 但是main函数里面并没有test()函数的具体实现方法,所以编译器会在处于同一个编译单元的其他地方找,也就是在 “ function1.h ” 头文件:

而在头文件“function1.h” 中,编译器只发现了函数的定义,也没有找到函数的具体定义:

所以,连接器就会从其他编译单元的导出符号表中寻找与函数test()相同名字的符号,试图找出test()函数的具体实现方法,而在编译单元function.cpp中发现了函数的实现方法,所以连接器就将两个单独的编译单元连接在一起,而在内部无法知道函数具体是如何实现的,只能通过查找外部编译单元的符号,叫做“外部符号”,而这种类型就叫 “ 外部连接类型 ” :

而模板类又与普通情况不同,模板类因其本身具有 “ 不确定性 “ 特点,在C++的规则里,模板类在编译时需要一个具体化的过程。我们将以上的项目做一些修改:

fuction.h:

#ifndef _FUNCTION_H_
#define _FUNCTION_H_template <class T_ELE>
class function
{
public:void test();
}#endif

function.cpp:

#include "function.h"
#include <iostream>template <class T_ELE>
void function<T_ELE>::test()
{//do anything~
}

main.cpp:

#include "function.h"void main()
{function<int>::test();
}

此时main.cpp 中的调用了使用类模板的test()函数,编译器在编译期间寻找编译单元内部并没有找到具体的实现方法,只找到了函数的声明,所以,寻找函数具体实现方法这个任务就交给了链接器,而连接器在外部的编译单元function.cpp 里找到了函数的具体实现方法:

但是,问题来了,在C++中由于模板类的自身不确定性,当一个模板没有被调用时,它就不会被具体化出来,也就是说在一个编译单元里,如果使用模板类的函数没有被其他函数调用的话,是没有生成二进制代码的,因为编译器并不知道这个函数是属于哪个类型(int,float,等等),所以无法给这个函数分配合适的内存空间,只有当其他函数调用模板类的函数时,才能确定类型,模板类才能被具现化。

这时,很多人就会有一个这样的误解:我不是在主函数里面调用了模板类的函数了嘛?为啥还是错误呢?请注意,我们再来回顾下这个错误:

该错误描述为:无法解析的外部符号。我们再回顾下上面说过的,本项目一共有两个编译单元,一个是main,一个是function,而编译过程是每个编译单元单独编译过后再交给连接器进行连接的,也就是说在连接器之前两个编译单元就已经进行了编译,而在主函数main里面调用外部编译单元时,由于另外一个编译单元function在编译时模板类没有被调用而没有得到具现化,从而导致了连接器在函数主函数里调用了模板类函数,但是找不到具体的实现方法的情况,从到就出现了开头的错误:LNK2019 无法解析的外部符号。

知道了错误的根源,我们就可以根治这种情况,总得来说就是模板类没有具现化,那我们就让它具现化就好了,所以总结了以下几个解决方案也得到了很好的解析:

1.在主函数包含头文件时将实现模板类的函数也包含进来。原因:一个编译单元内包含了.cpp文件以及被include 的头文件,如果将实现模板类的函数文件.cpp也包含进来,那么主函数调用就给了模板类函数一个具现化的机会。

2.将模板类的实现方法写在头文件里面。原因:同上,将实现写在头文件里面,那么主函数调用就给了模板类函数一个具现化的机会。

3.在实现模板类的文件中调用一下模板类。原因:调用一下让模板类函数得到具现化。

【c++】因模板类导致的 LNK2019 错误:“ 无法解析的外部符号 ” 详解相关推荐

  1. php7自定义异常处理,基于PHP7错误处理与异常处理方法(详解)

    PHP7错误处理 PHP 7 改变了大多数错误的报告方式.不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出. 这种 Error 异常可以像 Exception 异常一 ...

  2. 暗黑3服务器维护能登录,暗黑3登陆错误原因及解决办法详解

    暗黑3登陆错误原因及解决办法详解 2012-10-15 09:06:03来源:游戏下载编辑:评论(0) 暗黑3报错ERROR解决方法,全部暗黑3报错汇总,全部报错汇总解答.小编将玩家遇到的各种暗黑3安 ...

  3. Qt编译报错 LNK2019:无法解析的外部符号

    Qt编译项目报错"LNK2019:无法解析的外部符号"时,按如下操作解决: 到该项目构建生成build的路径下删除build文件夹,再重新到Qt中对项目执行"清除-qma ...

  4. 页错误 Page Fault /缺页异常 详解

    ​​​​​目录 ​​​​​​ 1. 第一部分:如果你看得懂 1.1 页错误定义 1.2 页错误的处理 2. 第二部分:如果你看不懂上面的,请看这里 2.1. 举例子(背景) 2.1.1 进程及页映射 ...

  5. 中科大-计算机类考研真题(初试笔试真题详解+复试笔试机试真题详解+面试问题汇总分析)

    中科大-计算机类考研真题(初试笔试真题详解+复试笔试机试真题详解+面试问题汇总分析) 初试笔试真题2003年~2019年:答案+详解 复试面试问题总结:问题汇总+详解分析 复试面试经验总结:个人小结 ...

  6. 错误 LNK2019,无法解析的外部符号__imp____iob_func; 无法解析的外部符号 __imp__fprintf 的解决方法。

    每次看到的LNK2019 的报错就有种崩溃的感觉,尤其是刚接触vc++的程序员. 我们经常会在网上搜索大神的技术文档,大神们提供的源代码都表示没有bug直接可以使用,但是我们下载以后发现各种报错,看到 ...

  7. 笔记LNK2019:无法解析的外部符号

    1.一般出现"LNK2019"错误都是库文件没添加造成的. 项目-->属性-->配置属性-->链接器->输入-->附加依赖项 在其中加入所需库文件,同 ...

  8. java的连接 初始化_java类从加载、连接到初始化过程详解

    Java代码在编译后会转化成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化成汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令. 类加载 ...

  9. Bug(七)—— error LNK2019:无法解析的外部符号

    前言 error LNK2019,这类问题一般是因为链接lib库文件时的问题. 所以只要正确的进行lib库文件的链接,这类问题就会得到解决. 解决方法 lib库文件包含了DLL中函数的想关信息,因此我 ...

最新文章

  1. eclipse 环境下 FreeMarker 编辑器插件
  2. 上struts2的xml在lt;result type=quot;redirectquot;gt;参数问题
  3. CentOS中启动Jar包、后台启动、查看输出日志、查看服务进程、杀死进程
  4. HDU 4883 Best Coder Round 2 TIANKENG’s restaurant 解读
  5. [NOIP2015] 子串
  6. android 百度地图api密钥,Android百度地图开发获取秘钥之SHA1
  7. android 联系数据库
  8. 网络编程-关于get请求与post请求
  9. POJ - 2182 Lost Cows【线段树】
  10. 计算与推断思维 十七、更新预测
  11. 买断变订阅!苹果第一付费软件被骂上热搜 官方回应
  12. 次表面散射材质_游戏开发者怎么做出以假乱真的画面效果?大气散射渲染了解一下...
  13. 【房屋租赁管理模块的设计与实现】
  14. STM32F1下载程序方法
  15. 30分钟!用Django做一个迷你的Todolist!下篇!
  16. HAL定时器库函数和定时器的解析
  17. html excel 在线编辑,利用js实现在线编辑excel表格代码
  18. Python实现对某微博用户数据分析
  19. Linux文档编辑命令
  20. android学习笔记之磁场传感器制做指南针

热门文章

  1. 电流和电压的产生原理
  2. win 10系统安装myeclipse 9.1 破解问题
  3. Eclipse3.1.2 汉化 过程 中文版
  4. [扫盲] XAMPP是什么东西?
  5. isNaN函数的使用方法
  6. GmSSL证书生成及验证C/S通信双向认证
  7. Responder入门理解笔记
  8. C#复习之委托(Delegate)和事件(Event)
  9. latex文献怎么弄_Latex 中如何制作参考文献 (以ApJ为例)
  10. 百视通与微软共同宣布9月在华发布Xbox One