欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

虚函数的实质——虚函数表

程序员文章站 2022-07-12 08:13:05
...

目录

 

虚函数的实质——虚函数表

虚函数表是什么?

虚函数表长什么样?

证明了确实存在隐藏的虚函数表指针

派生类指针转换为基类类型的实质

当基类指针指向派生类对象时,虚函数表会如何变化?


虚函数的实质——虚函数表

虚函数表是什么?

虚函数表实质上就是静态指针数组,里面存储着每个成员函数的地址。

虚函数表长什么样?

虚函数的实质——虚函数表

 

这里除了父类Base中仅成员函数Func2没被声明为虚函数是从基类中继承过来的其他的成员函数全部将父类的同名成员函数替换。

虚函数表中存着每个成员函数的真实地址,比如当我们在父类中声明虚函数时,派生类的相应同名函数体的将其屏蔽替换。此时,派生类虚函数表中的这个函数它的地址是本类中新声明的函数地址,并不是基类同名函数的地址。如果我们不在父类中声明虚函数,派生类的成员函数是从基类中继承过来的,此时虚函数表中存储的函数地址是基类中的函数地址。

证明了确实存在隐藏的虚函数表指针

代码示例:

#include <iostream>  
#include <string>  
using namespace std;  
  
class Cstudent  
{  
private:  
    string name;  
    float mark;  
public:  
    Cstudent(string name, float mark)  
    {  
        this->name = name;  
        this->mark = mark;  
    }  
    ~Cstudent()  
    {  
        cout << "调用Cstudent的析构函数" << endl;  
    }  
    virtual void ShowInf() // 虚函数表指针占用4个字节存储内存  
    {  
        cout << this->name << "的成绩为" << this->mark << "分" << endl;  
    }  
};  
  
class CTemplatestudent  
{  
private:  
    string name;  
    float mark;  
public:  
    CTemplatestudent(string name, float mark)  
    {  
        this->name = name;  
        this->mark = mark;  
    }  
    ~CTemplatestudent()  
    {  
        cout << "调用Cstudent的析构函数" << endl;  
    }  
    void ShowInf()  
    {  
        cout << this->name << "的成绩为" << this->mark << "分" << endl;  
    }  
};  
  
int main()  
{  
    cout << "Cstudent所占用的空间为" << sizeof(Cstudent) << endl; // 结果为36=32+4  
    cout << "CTemplatestudent所占用的空间为" << sizeof(CTemplatestudent) << endl; // 结果为32  
}  

 

派生类指针转换为基类类型的实质

指针指向的起始地址并不随数据类型的变化而变化,但是它指向的有效区域确随着数据类型的变化而变化。

虚函数的实质——虚函数表

 

在此例中,基类指针只指向派生类从基类中继承的东西(不考虑virtual时),因此指针里面的地址并不重要,重要的是指针的类型和对象的类型,这两个因素决定了指针指向的有效区域。

当基类指针指向派生类对象时,虚函数表会如何变化?

基类指针智慧指向派生类对象中与基类成员函数同名的函数,因为虚函数表只会把与基类成员函数同名的函数地址传进来。

相关标签: C++拓展知识