• 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的例子

    [csharp] view plaincopy
    1. Class Parent  
    2.   
    3. {  
    4.   
    5. public: Parent() { }   
    6.   
    7. ~Parent() {    
    8.   
    9. ClearALL();    
    10.   
    11. }    
    12.   
    13. void ClearALL()   
    14.   
    15. {    
    16.   
    17. ThePure();   //调用自身的纯虚函数,包装一下是因为直接调用编译器会识别出这样调用是有问题的!  
    18.   
    19. }   
    20.   
    21.  virtual bool ThePure() = 0 ;  
    22.   
    23. };   
    24.   
    25. class Child : public Parent  
    26.   
    27. {  
    28.   
    29. public: Child() { }    
    30.   
    31. ~Child() { }  //The implementation of the pure virtual function  virtual bool ThePure()    
    32.   
    33. {    
    34.   
    35. return true;   
    36.   
    37. }   
    38.   
    39. };     
    40.   
    41. void main()  
    42.   
    43. {  
    44.   
    45.  Child c;  
    46.   
    47. }  

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

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

    [csharp] view plaincopy
    1. //不过我在VC6里没有问题  
    2.   
    3.   
    4.   
    5. class Base   
    6.   
    7. {  
    8.   
    9. public:  
    10.   
    11.     virtual void function() = 0;  
    12.   
    13. };  
    14.   
    15.   
    16.   
    17. class B : public Base  
    18.   
    19.   
    20.   
    21. {  
    22.   
    23. public:  
    24.   
    25.     virtual void function()   
    26.   
    27.     {  
    28.   
    29.         cout<<"pure function call in B"<<endl;  
    30.   
    31.   
    32.   
    33.     }  
    34.   
    35. };  
    36.   
    37.   
    38.   
    39. class A   
    40.   
    41. {  
    42.   
    43. public:  
    44.   
    45.     A(B* b):_b(b) {}  
    46.   
    47.     ~A()   
    48.   
    49.     {  
    50.   
    51.         _b->function();  
    52.   
    53.     }  
    54.   
    55.     B* _b;  
    56.   
    57. };  
    58.   
    59.   
    60.   
    61. B b;  
    62.   
    63. a(&b);  
    64.   
    65.   
    66.   
    67. int main()  
    68.   
    69. {  
    70.   
    71.     return 0;  
    72.   
    73. }  
    这种情况在某些编译器下会出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

  • 相关阅读:
    转载的log4cplus使用指南
    linux下安装log4cplus
    MongoDB常用命令
    ios UIButton改背景
    ios发送邮件
    oracle数据库 in 结果字段的拆分
    Server returned HTTP response code: 505
    ORA-01795:列表中的最大表达式数为1000
    ajax post请求
    oracle 同义词
  • 原文地址:https://www.cnblogs.com/dracohan/p/3402054.html
Copyright © 2020-2023  润新知