C++ 虚函数及虚函数表详解

 更新时间:2021年11月03日 10:23:51   作者:dwell548560  
这篇文章主要介绍了c++ 虚函数及虚函数表详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定。

#include <iostream>
using namespace std;
class A
{
public:
    int i;
    virtual void func() {}
    virtual void func2() {}
};
class B : public A
{
    int j;
    void func() {}
};
int main()
{
    cout << sizeof(A) << ", " << sizeof(B);  //输出 8,12
    return 0;
}

 在 32 位编译模式下,程序的运行结果是:

8, 12

如果将程序中的 virtual 关键字去掉,输出结果变为:

4, 8

A * p = new B() 实现多态

对比发现,有了虚函数以后,对象所占用的存储空间比没有虚函数时多了 4 个字节。实际上,任何有虚函数的类及其派生类的对象都包含这多出来的 4 个字节,这 4 个字节就是实现多态的关键——它位于对象存储空间的最前端,其中存放的是虚函数表的地址。

每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中都放着该虚函数表的指针(可以认为这是由编译器自动添加到构造函数中的指令完成的)。 

没有覆盖时的子类,可以看到子类的虚函数表的前面是基类离得虚函数

有覆盖就是

子类对象地址为什么能赋值给父类对象指针?

因为,子类对象地址赋值给父类对象指针,父类对象指针就指向了子类的对象空间,父类操作子类的范围是有限制的,只能操作到子类中父类的范围。

基类和子类各有自己的虚函数表vtbl;不管是基类还是子类实例都会在其内存的开头自动创对象即虚函数表指针vptr, 用来访问所在类的虚函数表

想要实现多态,需要动态绑定,需要父类的指针或父类的引用

父类方法为虚方法,子类覆盖父类的虚方法,才能达到多态

子类中父类没有的方法,父类指针也无法访问到,父类指针只能访问到父类自己有的范围

子类要覆盖父类的方法,就是要函数名参数都必须一样才叫覆盖

再看一个例子

class A {
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};
class B : public A {
public:
    virtual void vfunc1();
    void func1();
private:
    int m_data3;
};
class C: public B {
public:
    virtual void vfunc2();
    void func2();
private:
    int m_data1, m_data4;
};

子类继承父类,子类中有父类的同名方法,访问的是子类的方法,子类会隐藏父类所有的同名方法,即使父类有一个同名的参数不同的方法也是如此。 

多重继承(无虚函数覆盖)

下面,再让我们来看看多重继承中的情况,假设有下面这样一个类的继承关系。注意:子类并没有覆盖父类的函数。 

对于子类实例中的虚函数表,是下面这个样子:

我们可以看到:

1)  每个父类都有自己的虚表。

2)  子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明顺序来判断的) 

这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。 

多重继承(有虚函数覆盖) 

下面我们再来看看,如果发生虚函数覆盖的情况。 

下图中,我们在子类中覆盖了父类的f()函数。 

下面是对于子类实例中的虚函数表的图: 

我们可以看见,三个父类虚函数表中的f()的位置被替换成了子类的函数指针。这样,我们就可以任一静态类型的父类来指向子类,并调用子类的f()了。

任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法,

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • C++ com编程学习详解

    C++ com编程学习详解

    这篇文章主要介绍了C++ COM编程的学习过程,在C++中,可以使用抽象基类来实现COM接口,需要的朋友可以参考下,希望能够给你带来帮助
    2021-09-09
  • 用C语言实现猜数字

    用C语言实现猜数字

    这篇文章主要为大家详细介绍了用C语言实现猜数字,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C语言结构体使用之链表

    C语言结构体使用之链表

    这篇文章主要介绍了C语言结构体使用之链表,下面文章主要围绕结构体的概念和用法、结构体数组和结构体指针、包含结构体的结构体、结构体搭建链表方法、结构体及链表在产品应用场景等多个主题展开链表的相关资料,需要的小伙伴可以参考一下
    2022-03-03
  • 用c语言编写一个通讯录代码详解

    用c语言编写一个通讯录代码详解

    大家好,本篇文章主要讲的是用c语言实现一个通讯录代码详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 基于make命令与makefile文件详解

    基于make命令与makefile文件详解

    下面小编就为大家分享一篇基于make命令与makefile文件详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • c语言实现向上取整计算方法

    c语言实现向上取整计算方法

    这篇文章主要介绍了c语言实现向上取整计算方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C++实现LeetCode(50.求x的n次方)

    C++实现LeetCode(50.求x的n次方)

    这篇文章主要介绍了C++实现LeetCode(50.求x的n次方),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言实现停车场项目

    C语言实现停车场项目

    这篇文章主要为大家详细介绍了C语言实现停车场项目,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C++Primer笔记之关联容器的使用详解

    C++Primer笔记之关联容器的使用详解

    本篇文章对C++Primer 关联容器的使用进行了详细的分析介绍。需要的朋友参考下
    2013-05-05
  • c++ signal实现发送信号

    c++ signal实现发送信号

    这篇文章主要为大家详细介绍了c++ signal实现发送信号的相关知识,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01

最新评论