zoukankan      html  css  js  c++  java
  • C++ 虚函数在基类与派生类对象间的表现及其分析

    近来看了侯捷的《深入浅出MFC》,读到C++重要性质中的虚函数与多态那部分内容时,顿时有了疑惑。因为书中说了这么一句:使用“基类之指针”指向“派生类之对象”,由该指针只能调用基类所定义的函数,如果要让基类的指针使用派生类中定义的函数,就将该函数定义为虚函数

     但在“Object slicing与虚函数”这一小节给出了一个及其经典的例子,它指出,在向上(即向基类)强制转型时,会造成对象内容的被切割

     下面用示例进行说明:

     1 #include "stdafx.h"  
     2 #include <iostream>  
     3 using namespace std;  
     4   
     5 class A  
     6 {  
     7 public:  
     8     virtual void fn(){cout<<"A fn"<<endl;}  
     9 };  
    10   
    11 class B: public A  
    12 {  
    13 public:  
    14     virtual void fn(){cout<<"B fn"<<endl;}  
    15 };  
    16   
    17 int main(int argc, char* argv[])  
    18 {  
    19     B b1;  
    20     A a1=(A)b1;  
    21     A * a2=(A*)&b1;  
    22     a1.fn();  
    23     a2->fn();  
    24     return 0;  
    25 }  

     结果如下:

    通过调试分析其内存模型如下:

    可知,通过A  a1=(A)b1传值时,对象中指向虚函数表的指针__vfptr值不同,但是通过A *a2=(A*)&b1传址操作时,对象中指向虚函数表的指针__vfptr值是相同的,调用的是类B对象的虚函数表中虚函数fn()。注意,对象调用的是哪个类的虚函数就要看类对象的虚函数表中的函数是哪一个。这句话也好理解,a1虚函数表中fn()是A::fn(),a2虚函数表中fn()是B::fn(),所以出现以上结果。

    在如下包含父类的父类的继承中:

     1 class A
     2 {
     3 public:
     4 virtual void fn(){cout<<"A fn"<<endl;}
     5 };
     6 
     7 class B: public A
     8 {
     9 public:
    10 virtual void fn(){cout<<"B fn"<<endl;}
    11 };
    12 
    13 class C: public B
    14 {
    15 public:
    16 };
    17 C c;
    18 A a1=(A)c;
    19 A * a2=(A*)&c;
    20 a1.fn();
    21 a2->fn();

     这时,a1虚函数表中fn()为A::fn(),a2虚函数表中fn()为B::fn(),因为类C对象的虚函数表中fn()为B::fn(),a2中指向虚函数表的指针值与类C对象指向虚函数表的指针值相同。

    侯捷的书中有句话是这么对它进行解释的:由于(A)b1.fn()是传值而非传地址操作,编译器以所谓的拷贝构造函数把A对象内容复制了一份,使得b1的虚函数表内容与A对象的虚函数表内容相同

    看来,得多读圣贤书,读懂读透啊!

  • 相关阅读:
    洛谷 P2700 逐个击破
    洛谷 P1503 鬼子进村
    洛谷 P1556 幸福的路
    洛谷 P1490 买蛋糕
    洛谷 P2507 [SCOI2008]配对
    code vs 3305 水果姐逛水果街Ⅱ
    通过idea远程调试
    【Cocos2d-x JavaScript Binding】
    ☀【SeaJS】SeaJS Grunt构建
    -_-#【Better Code】throttle / debounce
  • 原文地址:https://www.cnblogs.com/Romi/p/3329132.html
Copyright © 2011-2022 走看看