C++-不要在构造和析构函数中调用虚函数
在实习的单位搞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的例子
- Class Parent
- {
- public: Parent() { }
- ~Parent() {
- ClearALL();
- }
- void ClearALL()
- {
- ThePure(); //调用自身的纯虚函数,包装一下是因为直接调用编译器会识别出这样调用是有问题的!
- }
- virtual bool ThePure() = 0 ;
- };
- class Child : public Parent
- {
- public: Child() { }
- ~Child() { } //The implementation of the pure virtual function virtual bool ThePure()
- {
- return true;
- }
- };
- void main()
- {
- Child c;
- }
当C析构时,虚函数表里的 ThePure() 已经注销,那么父类 Parent 里的ClearALL() 里的ThePure()虚表指针就会指向一个空地址(成了 dangling pointer 了), 所以在Parent里调用 ClearALL() 就会出错了
(3)如果上面的情况还算直观的话,看看下面的一种造成 pure virtual function call的情况就更隐蔽了。
- //不过我在VC6里没有问题
- class Base
- {
- public:
- virtual void function() = 0;
- };
- class B : public Base
- {
- public:
- virtual void function()
- {
- cout<<"pure function call in B"<<endl;
- }
- };
- class A
- {
- public:
- A(B* b):_b(b) {}
- ~A()
- {
- _b->function();
- }
- B* _b;
- };
- B b;
- a(&b);
- int main()
- {
- return 0;
- }
这种情况在某些编译器下会出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++-不要在构造和析构函数中调用虚函数的更多相关文章
- EC笔记,第二部分:9.不在构造、析构函数中调用虚函数
9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...
- C++箴言:避免构造或析构函数中调用虚函数
如果你已经从另外一种语言如C#或者Java转向了C++,你会觉得,避免在类的构造函数或者析构函数中调用虚函数这一原则有点违背直觉.但是在C++中,违反这个原则会给你带来难以预料的后果和无尽的烦恼. 正 ...
- C++构造与析构函数中调用虚函数的问题
前些天想把以前写的内存池算法重写一遍,跨平台是第一目标,当时突发奇想,因为不愿意做成一大堆#if..#end,所以想利用C++的多态性,但是怎么让内存池完好退出却没想到自认为完美的方案.但是一个很偶然 ...
- C++ 笔记(二) —— 不要在构造和析构函数中调用虚函数
ilocker:关注 Android 安全(新手) QQ: 2597294287 class Transaction { //所有交易的 base class public: Transaction( ...
- 【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数
1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数, ...
- 在构造函数和析构函数中调用虚函数------新标准c++程序设计
在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函数.如果本类有该函数,调用的就是本类的函数:如果本类没有,调用的就是直接基类的函数:如果基类没有,调用的就是间接基类的函数,以 ...
- 读书笔记 effective c++ Item 9 绝不要在构造函数或者析构函数中调用虚函数
关于构造函数的一个违反直觉的行为 我会以重复标题开始:你不应该在构造或者析构的过程中调用虚函数,因为这些调用的结果会和你想的不一样.如果你同时是一个java或者c#程序员,那么请着重注意这个条款,因为 ...
- c++有关构造函数和析构函数中调用虚函数问题
今天看了一道迅雷的笔试题目,然后引起一段思考,题目如下: 下列关于虚函数的说法正确的是()A.在构造函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效.B.在析构函数中调用类自己的虚函数,虚函数的 ...
- 09——绝不在构造和析构函数中调用virtual函数
在base class构造期间,virtual函数不是virtual函数. 构造函数.析构函数中不要调用virtual函数.
随机推荐
- 【Todo】Nginx架构学习
要进行Web服务,绕不开的就是Nginx.这已经是大型网站的标配.对Nginx进行一定程度的深入学习. http://www.ituring.com.cn/article/4436 http://bl ...
- Android ViewPager刷新解析
ViewPager刷新解析 原本以为PagerAdapter类似于BaseAdapter 但是使用起来发现刷新还是有区别的 解析如下 先上Demo PagerAdapter的四大函数 getCount ...
- windows下重新安装TCP/IP协议栈
一.windows重装TCP/IP协议 前两天在windows下安装开发环境的时候,把系统的TCP/IP协议栈给搞跪了,导致系统无法ping localhost.无法在程序中创建socket等 ...
- android打开,保存图片到sd卡,显示图片
1.打开根目录下test.jpg Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getA ...
- DialogFragment 自定义弹窗
layout文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:a ...
- linux笔记:文件处理命令touch,cat,more,less,head,tail
命令名称:touch功能:新建文件命令所在目录:/bin/touch用法:touch 文件名 命令名称:cat功能:显示文件内容命令所在目录:/bin/cat用法:cat [-n] 文件名参数:-n ...
- python中的binascii
import binascii as B s = 'abcde' h = B.b2a_hex(s) # 字符串转16进制 '6162636465' h = B.hexlify(s) # 作用同上 s ...
- JavaScript访问修改css样式表
1.访问元素中style属性的css样式 可以根据属性的ID或name标签利用dom操作直接访问到内部的css样式,直接使用style对象访问 <div id="myid" ...
- hdu 4009 Transfer water(最小型树图)
Transfer water Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)To ...
- hdu 3853LOOPS (概率DP)
LOOPS Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others) Total Su ...