在实习的单位搞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. }
  1. 这种情况在某些编译器下会出pure virtual function call错误。主要的原因是因为全局变量的释放顺序不确定,全局变量A依赖全局变量B。如果编译器决定让B先释放,A后释放。那么,当A析构时,_b是一个dangling pointer。此时如果b对象的内存系统没有释放的话,那么bvptr表指向的是Basevptr,而不是B的。此时,_b->function()就指向了pure virtual function了。详细情况可以到看看
  1. http://www.cnblogs.com/whjiang/archive/2007/10/22/932880.html
  1. (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. Android最佳性能实践(一)——合理管理内存

    有不少朋友都问过我,怎样才能写出高性能的应用程序,如何避免程序出现OOM,或者当程序内存占用过高的时候该怎么样去排查.确实,一个优秀的应用程序,不仅仅要功能完成得好,性能问题也应该处理得恰到好处.为此 ...

  2. Android控件之Button(按钮控件)和ImageButton(图片按钮控件)

    一.Button和ImageButton特证: 1.共同特证: 都可以作为一个按钮产生点击事件 2.不同特证: Button有text的属性,ImageButton没有 ImageButton有src ...

  3. HBase启动和停止命令

    启动HBase集群: bin/start-hbase.sh 单独启动一个HMaster进程: bin/hbase-daemon.sh start master 单独停止一个HMaster进程: bin ...

  4. Kafka的配置文件详细描述

    在kafka/config/目录下面有3个配置文件: producer.properties consumer.properties server.properties (1).producer.pr ...

  5. 【转】java多态详解

    1.        Java中除了static和final方法外,其他所有的方法都是运行时绑定的.private方法都被隐式指定为final的,因此final的方法不会在运行时绑定.当在派生类中重写基 ...

  6. ECMAScript 6入门 - let和const命令

    详细学习链接: http://es6.ruanyifeng.com/#docs/let let命令 基本用法 ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命 ...

  7. redis命令集合

    一.连接控制 QUIT 关闭连接 AUTH (仅限启用时)简单的密码验证 二.适合全体类型的命令 EXISTS key 判断一个键是否存在;存在返回 1;否则返回0;DEL key 删除某个key,或 ...

  8. 数据库函数--nvl、coalesce、decode比较

    SQL中 nvl().coalesce().decode()这三个函数nvl(bonus,0) 2个参数 if bonus is null return 0 else return bonus,ora ...

  9. Android Drawable资源

    Android实现应用d动画效果:比如App第一次打开的开始动画等 有两种:GIF动画和代码实现. 第一种:借助于Gif制作工具软件实现.一般是和第三方开源的GifView(https://githu ...

  10. WebViewJavascriptBridge-Obj-C和JavaScript互通消息的桥梁

    转载至:http://www.cocoachina.com/ios/20150629/12248.html 译者:@coderyi9 本文翻译自Marcus Westin的开源框架WebViewJav ...