不知道诸位有没有过这样的经历:本是简单合法的 C++ 代码,但编译链接的时候却出现了如下的链接错误:
> error LNK2001: 无法解析的外部符号 __purecall
在解决这个问题之前,我们可以一起重现这个错误,先。新建一个 Win32 工程,打开 VS 的工程设置,修改如下项目:
将“启用 C++ 异常”设为“否”; 
将“基本运行时检查”设为“默认值”; 
将“缓冲区安全检查”设为“否(/GS-)”; 
将“启用运行时类型信息”设为“否(/GR-)”; 
将“忽略所有默认库”设为“是(/NODEFAULTLIB)”。 
然后,在源文件中输入如下的代码:
view plaincopy to clipboardprint?
#include <Windows.h>   
#include <tchar.h>   
void* operator new(size_t _Size)   
{   
return HeapAlloc(GetProcessHeap(), 0, _Size);   
}   
void operator delete(void* ptr)   
{   
HeapFree(GetProcessHeap(), 0, ptr);   
}   
class A   
{   
public:   
virtual void foo(void) = 0;   
};   
class B : public A   
{   
public:   
void foo(void)   
{   
OutputDebugString(_T("Hello, World!\r\n"));   
}   
};   
extern "C" void WinMainCRTStartup(void)   
{   
A* p = new B;   
p->foo();   
delete p;   
}  
#include <Windows.h>
#include <tchar.h>
void* operator new(size_t _Size)
{
return HeapAlloc(GetProcessHeap(), 0, _Size);
}
void operator delete(void* ptr)
{
HeapFree(GetProcessHeap(), 0, ptr);
}
class A
{
public:
virtual void foo(void) = 0;
};
class B : public A
{
public:
void foo(void)
{
OutputDebugString(_T("Hello, World!\r\n"));
}
};
extern "C" void WinMainCRTStartup(void)
{
A* p = new B;
p->foo();
delete p;
}
我来解释一下:修改工程设置实质上是剥离了工程对 VS 默认 CRT 的依赖,因此这里再使用的 C++ 内容就必须都要自己实现,包括 new、delete 以及程序的入口——也就是 WinMainCRTStartup。在代码输入完成后,构建这个工程,就可以如愿得到本文开头的那个链接错误了。
虽然工程并未构建成功,不过你仍然可以用反汇编工具打开编译器生成的 obj 文件,秘密就藏在其中。下面我只是简单说明一下 B 对象的构造过程,不列汇编代码了就。
调用 new 申请内存空间。 
调用 A::A,使用 A 类的虚表来初始化 A 类的子对象。 
调用 B::B,使用 B 类的虚表来初始化对象。 
问题就出现在第 2 步:A 类是个纯虚类,那么它的虚表是什么样子的?我在 obj 文件中找到了这个表,如下。
public ??_7A@@6B@
; const A::`vftable'
??_7A@@6B@      dd offset __purecall
如你所见,虽然 A::foo 是个纯虚函数,但编译器仍然为之准备了虚表中的一个栏位,只不过这个栏位的内容被一个名为 __purecall 的符号代替了。由于 __purecall 这个符号存在于默认的 CRT 之中,但我们先前又剥离了对 CRT 的依赖,因此在链接的时候就会出现 LNK2001 的链接错误。
解决方法很简单,再准备一个简单的 _purecall 就可以了:
view plaincopy to clipboardprint?
extern "C" int __cdecl _purecall(void)   
{   
return 0;   
}  
extern "C" int __cdecl _purecall(void)
{
return 0;
}
当然,其中最好加个断言什么的,以示这是一个不应到达的区域。
此外,VS 的 C++ 编译器对此种情况提供了特殊的支持,也就是使用 __declspec(novtable) 来定义无虚表的纯虚类。考虑如下代码:
view plaincopy to clipboardprint?
class __declspec(novtable) A   
{   
public:   
virtual void foo(void) = 0;   
};  
class __declspec(novtable) A
{
public:
virtual void foo(void) = 0;
};
这样亦能解决这个问题。

__purecall 链接错误相关推荐

  1. C++ 函数模板特化导致的多重定义链接错误

    转载请注明文章:C++ 函数模板特化导致的多重定义链接错误 出处:多客博图 标题说的可能不是很清楚,解释一下,函数模板,一般都是放在头文件里面,所以有些时候,我也会做一个特化,也放在这个头文件里面,当 ...

  2. C++编译-链接错误集合

    1,无法解析的外部符号,链接错误,原因:没找到某个符号(变量或函数)的定义体,一般是对应函数没实现,或第三方库没有添加到工程设置中 2,重复链接链接错误,一个定义体(实现体)被多个CPPP文件包含,导 ...

  3. boost::timer模块检查在同一程序中使用 Chrono 和 Timer 不会导致链接错误

    boost::timer模块检查在同一程序中使用 Chrono 和 Timer 不会导致链接错误 实现功能 C++实现代码 实现功能 boost::timer模块检查在同一程序中使用 Chrono 和 ...

  4. (ZT)VC++的链接错误LNK2001

    学习VC++时经常会遇到链接错误LNK2001,该错误非常讨厌,因为对于编程者来说,最好改的错误莫过于编译错误,而一般说来发生连接错误时,编译都已通过.产生连接错误的原因非常多,尤其LNK2001错误 ...

  5. 关于vs2008上的socket链接错误问题

    昨天想用socket做一个简单的windows程序, 先拿来了以前在vc6.0上做的一小段代码, 竟然发现在vs2008上不能运行.出现了好多链接错误, 研究了好半天也没有发现是怎么回事.>下来 ...

  6. 无限踩坑系列(6)-mySQL数据库链接错误

    mySQL数据库链接错误 错误1 错误2 长链接短连接 应用场景需要一直访问mySQL数据库,遇到如下错误: 错误1 释放已经释放的数据库链接conn.,或者,操作已经释放的数据库链接conn.或者失 ...

  7. 解决gdal集成libkml的链接错误

    作者:朱金灿 来源:http://blog.csdn.net/clever101 gdal库在集成libkml出现一些链接错误: 1>libkmldomD.lib(kml_factory.obj ...

  8. Duplicate Symbol链接错误的原因总结和解决方法[转]

    from:http://www.cocoachina.com/bbs/read.php?tid=177492 duplicate symbol是一种常见的链接错误,不像编译错误那样可以直接定位到问题的 ...

  9. linux 编译链接出错,Qt编译和链接错误

    为了演示 Qt Creator 的报错信息,我们刻意制造一个小 Bug.依然使用<Qt Creator使用教程(简明版)>一节中创建的项目和代码,双击 HelloWorld.pro,或者在 ...

最新文章

  1. 使用Remix编译和部署以太坊智能合约
  2. 面试官:谈谈Redis缓存和MySQL数据一致性问题
  3. 8-1日复习 模板函数 模板类
  4. Unity3D ShaderLab 物体相交
  5. ansible-playbook 手工编译安装nginx
  6. 贪心算法——洛谷(P1803)
  7. CXF WebService整合SpringMVC的maven项目
  8. linux正则表达式大全,正则表达式,正则表达式语法大全
  9. 多功能域名检测集合工具
  10. JS淘宝商品广告效果
  11. 山东腾飞科尔沁 国稻种芯·中国水稻节:内蒙沙漠万亩水稻
  12. 京东个人注册开店要怎么做?京东开店步骤介绍!
  13. Power oj 2837: 剑道万古如长夜(单调队列优化DP)
  14. POS标记——HMM模型
  15. 机器学习中的数学(上)
  16. Elasticsearch搜索引擎(一)——基础使用
  17. 拷贝pdf中的表格数据
  18. 五年北京,这个改变我命运的城市,终于要离开了(转)
  19. 浮点型数据规范以及规格化与非规格化数据(更新:原文疑问已解)
  20. 机器视觉学习系列四:身份证识别

热门文章

  1. python 错误与异常
  2. vue $emit $on 非父子非兄弟组件传值
  3. docker仓库harbor搭建
  4. php expat+DOM+SimpleXML XML读取
  5. 利用scrapy和MongoDB来开发一个爬虫
  6. Vim 自动文件头注释与模板定义
  7. Android_注解+反射代替findViewById()
  8. 纯CSS 实现组织架构图,学习
  9. Linux 与win双系统时间不统一的解决方法
  10. 如何识别未使用的CSS定义[关闭]