c++ 继承类强制转换时的虚函数表工作原理

本文通过简单例子说明子类之间发生强制转换时虚函数如何调用,旨在对c++继承中的虚函数表的作用机制有更深入的理解。

复制代码
#include<iostream>
using namespace std;

class Base
{
public:
    virtual void f()
    {
        cout<<"Base::f()"<<endl;
    }
};

class child1:public Base
{
public:
    virtual void f()
    {
        cout<<"child1::f()"<<endl;
    }

    virtual void a()
    {
        cout<<"child1::a()"<<endl;
    }
};

class child2:public Base
{
public:
    virtual void f()
    {
        cout<<"child2::f()"<<endl;
    }

    virtual void b()
    {
        cout<<"child2::b()"<<endl;
    }

    virtual void a()
    {
        cout<<"child2::a()"<<endl;
    }
};

int main()
{


    child1 c1;
    child2* pc21=(child2*)&c1;
    pc21->b();//输出 child1::a()
// pc21->a();//访问越界,程序运行时崩溃
child2 c2; child1* pc12=(child1*)&c2; pc12->a();//输出 child2::b() return 0; }
复制代码

结论:

  1、通常的类型强转是告诉编译器必须按照指定结构的内存布局来解析对应内存,如上例中“child2* pc21=(child2*)&c1; ”,编译器会把c1对应的内存来当做类child2的内存布局来解析。因为在类child2的虚函数表中,共存在三个函数,分别为f() b() a(),其中函数b()是第二个,因此编译器就会把对象c1对应的内存来当做类child2的内存布局来解析(注意内存里的内容不变,还是c1的,即为类child1的内存布局,在这里只有虚函数表),此时在类child1的虚函数表中也找第二个函数,找到了函数a(),因此输出“child1::a()”,运行正常。这种行为可能是危险的,若使用的内存布局并不适合真实内存,很可能造成访问越界等问题(如上例中的“pc21->a();”,这次就在类B的虚函数表中找第三个函数,结果没有找到(访问越界),函数运行时崩溃。),因此使用强制转换操作时应特别注意。

  2、通过上述例子可知,虚函数在虚函数表中的存储顺序是与声明顺序一致的,而不是虚函数名字的字符串排序,如本例中为f() b() a(),虽然编程时的自动补全提示框中显示的顺序是a() b() f(),但可能已经经过内部优化,这个就不太清楚了(也不是我们要研究的内容)。

 

posted @   xiaoxi666  阅读(1095)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
TOP
点击右上角即可分享
微信分享提示