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(),但可能已经经过内部优化,这个就不太清楚了(也不是我们要研究的内容)。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Coding迪斯尼

eactjs开发自制编程语言Monkey的编译器:高能技术干货之语法高亮2

1415
来自专栏程序员的SOD蜜

C#中?与??的区别

起初我也不知道C#中有??操作符,今天张鹏在查看我的MVC示例程序的时候问了这个问题,检查代码后发现,下面的代码是VS2010在生成MVC应用程序自己添加的: ...

2337
来自专栏黑白安全

PHP中echo,print,print_r,var_dump有什么区别

1.echo输出字符串或者数字,接受参数列表,不是函数,没有返回值。如果只是输出,echo更快

853
来自专栏程序生活

2017/6/9-Python文件读写的方法

# 使用斜杠“/”: "c:/test.txt"… 不用反斜杠就没法产生歧义了 # 将反斜杠符号转义: "c:\\test.txt"… 因为反斜杠是转义符,所...

3427
来自专栏公众号文章

Golang 入门系列(二)Go语言基础语法及需要注意的坑

上一章节我们已经了解了 Go 环境的配置,不了解的,请查看前面的文章 https://www.cnblogs.com/zhangweizhong/p/94599...

620
来自专栏顶级程序员

十条Python面试题陷阱,看看你是否会中招

每年的3-4月份是跳槽的高峰期,无论是应聘Python web开发,爬虫工程师,或是数据分析,还是自动化运维,都涉及到一些基础的知识!我挑了一些Python的基...

1382
来自专栏抠抠空间

Django 2.0 新款URL配置详解

Django2.0发布后,很多人都拥抱变化,加入了2的行列。 但是和1.11相比,2.0在url的使用方面发生了很大的变化,下面介绍一下:

2685
来自专栏流媒体

C++输入输出流

681
来自专栏从零开始学自动化测试

python笔记14-读取yaml配置文件

yaml简介 1.yaml [ˈjæməl]: Yet Another Markup Language :另一种标记语言。yaml 是专门用来写配置文件的语言,...

5198
来自专栏xingoo, 一个梦想做发明家的程序员

结构体的优化声明

声明一个结构体的时候,因为考虑到内存的对齐。例如,int型的变量,需要4个字节,那么它在存储的时候就需要在地址能够被4个字节整除的地方开始申请。 例如我们申请下...

18210

扫码关注云+社区

领取腾讯云代金券