C++多态,虚函数作用及底层实现原理

本文详细阐述了C++中虚函数的作用及其底层实现原理。解释了如何通过虚函数表和虚函数指针来实现动态绑定,使代码具备多态特性。并通过示例展示了单类继承与多类继承情况下虚函数表的布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简述C++虚函数作用及底层实现原理

1.foreword

C++是面向对象程序设计,其包括3项特点:
(1)数据抽象:接口和实现分离
(2)继承:父类和子类
(3)多态:动态绑定

本文讨论多态。

当父类希望子类重新定义某些函数时,用virtual关键字声明为虚函数。

当我们使用一个基类类型的引用或者指针,调用一个虚函数时就引发动态绑定/多态的发生。函数运行版本由传入的实参类型决定。可以用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。

父类指针好像有“多种类型”。这是一种泛型技术,试图用不变的代码实现可变的算法,比如模板技术,虚函数技术等。

引用或者指针的静态类型与动态类型不同这一事实,是C++支持多态的核心。

上述这句话选自《C++ Primer》,颇有玄门正宗之感。复杂的技术根植于底层的原理,所以搞清原理方可深入浅出。

当我们使用基类的引用、指针去调用基类中定义的一个虚函数时,并不知道该函数真正作用的对象是什么类型,可能是一个基类对象,也可能是一个派生类对象,这一切直到运行时才可知道。所以多态又称运行时绑定/动态绑定。

对于非虚函数的调用在编译时即可确定,哪个对象,哪个方法,地址是确定的。

2.虚函数底层实现原理

当你记住上面的概念时,它仅是概念。但当真正了解底层原理后,发现其中妙不可言。

如果让你来实现虚函数的功能?你会怎么实现?

复杂的代码?高深的原理?其实C++中实现的非常接地气。

虚函数是通过虚函数表和虚函数指针来实现的。

该表一般位于某类型的对象实例在内存中的最开始的位置。

单类继承

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

父类对象其在内存中布局示意如下:
这里写图片描述

虚函数表的尾部为虚函数表的结束结点。

再定义一个子类,此时并不覆盖父类的虚函数:

class Derived :public Base {
public:
    virtual void f1() { cout << "Derived::f1()" << endl; }
    virtual void g1() { cout << "Derived::g1()" << endl; }
    virtual void h1() { cout << "Derived::g1()" << endl; }
};

这里写图片描述

此时可以得知:
(1)虚函数按照声明顺序放在表中;
(2)父类的虚函数,排在子类虚函数之前。

当我们把子类中的函数覆盖时:

class Derived :public Base {
public:
    // f() override
    void f() { cout << "Derived::f1()" << endl; }
    virtual void g1() { cout << "Derived::g1()" << endl; }
    virtual void h1() { cout << "Derived::g1()" << endl; }
};

这里写图片描述

此时可以得知:
(1)子类覆盖的虚函数,放在原来父类该虚函数的位置;所以当父类指针指向该子类对象时,调用方法就会调用子类重载的方法;
(2)没有被覆盖的虚函数依旧。

多类继承

当发生多类继承时:

这里写图片描述

虚函数表内存排列示意如下:

这里写图片描述

此时可以得知:
(1)每个继承的父类,都有自己的虚函数表;
(2)子类虚函数,放在第一个声明顺序的父类的表中。

当子类虚函数重写时,此时类的继承为:

这里写图片描述

子类将f( )函数重写,则内存中的排列为:

这里写图片描述

此时我们可以得知:
(1)三个父类虚函数表中的f( )函数被替换为子类函数指针。因此当我们用任一静态类型的父类指针来指向子类时,调用f( )时就调用的子类的f( )。


参考资料:
[1] http://www.cnblogs.com/webary/p/4731457.html

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值