在实习的单位搞CxImage库时不知为什么在Debug时没有问题,但是Release版里竟然跳出个Pure virtual function call error! 啥东西呀,竟然遇上了,就探个究竟吧!

MSDN上的解释

http://forums.msdn.microsoft.com/zh-CN/clr/thread/bfa759a8-0cc0-4d65-8711-d2d0d6765687/

这时讲得很详细

http://www.artima.com/cppsource/pure_virtual.html

看看Codeproject上的一个例子

http://www.codeproject.com/KB/cpp/PureVirtualFunctionCall.aspx

(1)出现 Pure virtual function call 的原因是:

the child destructor is called and finished, so, we don’t have an object of type child now, but the current object (which is only being destructed) is of type Parent, so all calls in the destructor are calls to functions in this object. So, you can get a pure virtual function.

继承类的对象析构被调用,而且完成了释放,那么现在这个对象就不存在了,但是当前的对象(正在释构的父类对象)却要调用其子类的虚函数实现(因为自身是纯虚函数),所以就会出现Pure virtual function call error!

(2) 由面向对象的概念知,对象的析构是子类先析构再到父类析构,所以如果在父类中要调用自身的虚纯数将会很危险了,而且在是运行时出现的。

以下是codeproject的例子

  1. Class Parent
  2. {
  3. public: Parent() { }
  4. ~Parent() {
  5. ClearALL();
  6. }
  7. void ClearALL()
  8. {
  9. ThePure();   //调用自身的纯虚函数,包装一下是因为直接调用编译器会识别出这样调用是有问题的!
  10. }
  11. virtual bool ThePure() = 0 ;
  12. };
  13. class Child : public Parent
  14. {
  15. public: Child() { }
  16. ~Child() { }  //The implementation of the pure virtual function  virtual bool ThePure()
  17. {
  18. return true;
  19. }
  20. };
  21. void main()
  22. {
  23. Child c;
  24. }

当C析构时,虚函数表里的 ThePure()  已经注销,那么父类 Parent 里的ClearALL() 里的ThePure()虚表指针就会指向一个空地址(成了 dangling pointer 了), 所以在Parent里调用 ClearALL() 就会出错了

(3)如果上面的情况还算直观的话,看看下面的一种造成 pure virtual function call的情况就更隐蔽了。

  1. //不过我在VC6里没有问题
  2. class Base
  3. {
  4. public:
  5. virtual void function() = 0;
  6. };
  7. class B : public Base
  8. {
  9. public:
  10. virtual void function()
  11. {
  12. cout<<"pure function call in B"<<endl;
  13. }
  14. };
  15. class A
  16. {
  17. public:
  18. A(B* b):_b(b) {}
  19. ~A()
  20. {
  21. _b->function();
  22. }
  23. B* _b;
  24. };
  25. B b;
  26. a(&b);
  27. int main()
  28. {
  29. return 0;
  30. }
这种情况在某些编译器下会出pure virtual function call错误。主要的原因是因为全局变量的释放顺序不确定,全局变量A依赖全局变量B。如果编译器决定让B先释放,A后释放。那么,当A析构时,_b是一个dangling pointer。此时如果b对象的内存系统没有释放的话,那么b的vptr表指向的是Base的vptr,而不是B的。此时,_b->function()就指向了pure virtual function了。详细情况可以到看看
http://www.cnblogs.com/whjiang/archive/2007/10/22/932880.html
(5)论坛上关于出现pure virtual function call 的情况总结: 

1. 基类构造器直接调用虚函数

2. 基类析构器直接调用虚函数

3. 基类构造器间接调用虚函数

4. 基类析构器间接调用虚函数

5. Calling a virtual function via a dangling pointer.

(4)为了在遇到 pure virtual function call 时不致于程序蹦掉,可以实现在一基类的纯虚函数,但要记住找出原因后要删掉实现的代码

http://blog.csdn.net/kikikind/article/details/2645316

C++-不要在构造和析构函数中调用虚函数的更多相关文章

  1. EC笔记,第二部分:9.不在构造、析构函数中调用虚函数

    9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...

  2. C++箴言:避免构造或析构函数中调用虚函数

    如果你已经从另外一种语言如C#或者Java转向了C++,你会觉得,避免在类的构造函数或者析构函数中调用虚函数这一原则有点违背直觉.但是在C++中,违反这个原则会给你带来难以预料的后果和无尽的烦恼. 正 ...

  3. C++构造与析构函数中调用虚函数的问题

    前些天想把以前写的内存池算法重写一遍,跨平台是第一目标,当时突发奇想,因为不愿意做成一大堆#if..#end,所以想利用C++的多态性,但是怎么让内存池完好退出却没想到自认为完美的方案.但是一个很偶然 ...

  4. C++ 笔记(二) —— 不要在构造和析构函数中调用虚函数

    ilocker:关注 Android 安全(新手) QQ: 2597294287 class Transaction { //所有交易的 base class public: Transaction( ...

  5. 【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数

    1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数, ...

  6. 在构造函数和析构函数中调用虚函数------新标准c++程序设计

    在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函数.如果本类有该函数,调用的就是本类的函数:如果本类没有,调用的就是直接基类的函数:如果基类没有,调用的就是间接基类的函数,以 ...

  7. 读书笔记 effective c++ Item 9 绝不要在构造函数或者析构函数中调用虚函数

    关于构造函数的一个违反直觉的行为 我会以重复标题开始:你不应该在构造或者析构的过程中调用虚函数,因为这些调用的结果会和你想的不一样.如果你同时是一个java或者c#程序员,那么请着重注意这个条款,因为 ...

  8. c++有关构造函数和析构函数中调用虚函数问题

    今天看了一道迅雷的笔试题目,然后引起一段思考,题目如下: 下列关于虚函数的说法正确的是()A.在构造函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效.B.在析构函数中调用类自己的虚函数,虚函数的 ...

  9. 09——绝不在构造和析构函数中调用virtual函数

    在base class构造期间,virtual函数不是virtual函数. 构造函数.析构函数中不要调用virtual函数.

随机推荐

  1. 关于mysql的基础知识

    一.数据库的简介 什么是数据库? 数据的仓库,如:在atm的实例中我们创建一个db目录称之为数据库 什么是 MySQL.Oracle.SQLite.Access.MS SQL Server等 ? 他们 ...

  2. (八)shell中的循环结构

    1.for循环(1)要求:能看懂.能改即可.不要求能够完全不参考写出来.因为毕竟嵌入式并不需要完全重新手写shell,系统管理员(服务器运维人员,应用层系统级管理开发的才需要完全掌握shell) 这里 ...

  3. 转:从开源项目学习 C 语言基本的编码规则

    从开源项目学习 C 语言基本的编码规则 每个项目都有自己的风格指南:一组有关怎样为那个项目编码约定.一些经理选择基本的编码规则,另一些经理则更偏好非常高级的规则,对许多项目而言则没有特定的编码规则,项 ...

  4. Linux定时任务Crontab详解_定时备份

    文章来源:http://blog.chinaunix.net/uid-7552018-id-182133.html 今天做了个数据库的备份脚本,顺便系统得学习一下Linux下定时执行脚本的设置.Lin ...

  5. 转!!为什么要java环境变量配置?

    1. PATH环境变量.作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序.我们需要把 jdk安装目录下的bin目录增加到现有的PATH ...

  6. linux 相关学习记录

    (一)概念① 物理CPU实际Server中插槽上的CPU个数物理cpu数量,可以数不重复的 physical id 有几个② 逻辑CPU /proc/cpuinfo 用来存储cpu硬件信息的信息内容分 ...

  7. commonJS — 数组操作(for Array)

    for Array github: https://github.com/laixiangran/commonJS/blob/master/src/forArray.js 代码 /** * Creat ...

  8. phalcon count统计

    单表count: //How many robots are there? $number = Robots::count(); echo "There are ", $numbe ...

  9. Nodejs环境变量

    PATH,就是那个意思,没有特殊含义. NODE_PATH,将node_modules作为全局模块,多个安装目录用;分开.这样node在加载模块时首先会到项目目录下的node_modules目录加载相 ...

  10. js用ajax和jison在不同页面的php和html之间互相传值的方法

    <script> ;//这个id必须有,如果是空值,无法实现交互.有点郁闷.... var json; $.ajax({ url:"../member/wenzhanglishi ...