前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++多态虚函数动态绑定

C++多态虚函数动态绑定

作者头像
里克贝斯
发布2021-05-21 15:40:07
1.4K0
发布2021-05-21 15:40:07
举报
文章被收录于专栏:图灵技术域

定义

动态绑定是将一个过程调用与相应代码链接起来的行为。是指与给定的过程调用相关联的代码,只有在运行期才可知的一种绑定,它是多态实现的具体形式。

原理

C++中,通过基类的引用或指针调用虚函数时,发生动态绑定。引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指对的实际类型所定义的。 C++中动态绑定是通过虚函数实现的。而虚函数是通过一张虚函数表实现的。这个表中记录了虚函数的地址,解决继承、覆盖的问题,保证动态绑定时能够根据对象的实际类型调用正确的函数。 在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

缺点

1.动态绑定在函数调用时需要在虚函数表中查找,所以性能比静态函数调用稍低。 2.通过基类类型的指针访问派生类自己的虚函数将发生错误。

虚函数、动态绑定、运行时多态之间的关系: 虚函数是动态绑定的基础;动态绑定是实现运行时多态的基础。

动态绑定两个条件

(1) 只有虚函数才能进行动态绑定,非虚函数不进行动态绑定。 (2) 必须通过基类类型的引用或指针进行函数调用。

对应的有静态绑定 静态绑定是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型。静态绑定仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变。简单的讲,就是上下文无关,在编译时就可以确定其类型。

动态绑定与静态绑定 静态绑定:编译时绑定,通过对象调用 动态绑定:运行时绑定,通过地址实现

代码实例

C++

代码语言:javascript
复制
#include <iostream>
using namespace std;
class Base
{
public:
    virtual void f1()
    {
        cout<<"Base"<<endl;
    }
};
class Drived1:public Base
{
public:
    void f1()
    {
        cout<<"Drived1"<<endl;
    }
};
class Drived2:public Base
{
public:
    void f1()
    {
        cout<<"Drived2"<<endl;
    }
};
void Test(Base* pB)
{
    pB->f1 ();
}
int main()
{
    Base b;
    Drived1 d1;
    Drived2 d2;
    Test(&b);
    Test(&d1);
    Test(&d2);
    return 0;
}

输出结果: Base Drived1 Drived12

多继承中的问题

声明一个车(vehicle)基类,有Run、Stop等成员函数,由此派生出自行车(bicycle)类、汽车(motorcar)类,从bicycle和motorcar派生出摩托车(motorcycle)类,它们都有Run、Stop等成员函数。观察虚函数的作用。 其中令基类(vehicle)的Run和Stop函数设为虚函数

代码:

代码语言:javascript
复制
#include<iostream>
using namespace std;

class vehicle{
public:
    virtual void Run()const{cout<<"Vehicle Run"<<endl;}
    virtual void Stop()const{cout<<"Vehicle Stop"<<endl;}
};

class bicycle:public vehicle{
private:
    int Height;
public:
    void Run()const{cout<<"Bicycle Run"<<endl;}
    void Stop()const{cout<<"Bicycle Stop"<<endl;}
};

class motorcar:public vehicle{
private:
    int SeatNum;
public:
    void Run()const{cout<<"Motorcar Run"<<endl;}
    void Stop()const{cout<<"Motorcar Stop"<<endl;}
};


class motorcycle:public bicycle,public motorcar{
private:
public:
    void Run()const{cout<<"Motorcycle Run"<<endl;}
    void Stop()const{cout<<"Motorcycle Stop"<<endl;}
};

void fun(vehicle *ptr)
{
    ptr->Run();
    ptr->Stop();
}

void fun(motorcycle *ptr)
{
    ptr->Run();
    ptr->Stop();
}

int main()
{
    vehicle v;
    bicycle b;
    motorcar m;
    motorcycle x;
    fun(&v);
    fun(&b);
    fun(&m);
    fun(&x);
}

程序类中类vehicle,motorcar,bicycle均属于同一个类组,而且是通过公有派生来的,因此满足赋值兼容规则。同时基类vehicle的函数成员Run和Stop声明为虚函数,程序中使用对象指针来访问函数成员,完成了动态绑定。

为什么motorcycle单独设置了一个函数(使用指针)?

此时如果还用上面的第一个fun函数对于vehicle则产生二义性(多继承),解决方法是使用虚基类(注意不是虚函数)或者重载,不使用动态绑定。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 原理
  • 缺点
  • 动态绑定两个条件
    • 代码实例
    • 多继承中的问题
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档