笔记:C++虚表函数

什么是虚函数,就是函数名前面加一个 virtual

举例:

class  base{

public:

        void function1()

        {

        printf("funtion");

        }

   virtual viod funtion2()

        {

        printf("funtion2");

        }

}

base a;

a.function1();

a.function2();  

用结构体对象调用,他两没有任何区别 都是属于直接调用  call  地址

base* pbase;

pbase=&a;

pbase->function1();

pbase->function2();

用指针调用的时候,function2是属于间接调用 call dword[edx]; 

指针调用virtual 函数的时候 是属于间接call

sizeof(base)=12;当结构体里有虚函数的时候 类的大小会多出4个字节 ,不管加几个虚函数都是只多4个字节 

多出来的4个字节在对象的首地址 在所有元素最前面

这个4个字节是一个地址,指向虚函数表,虚函数表里存着这个结构里所有虚函数的地址

比如第二个虚函数调用地址就是 call  dword[edx+4]

虚函数表里只存储虚函数的地址 跟不是virtual的函数没有关系

函数指针调用虚表函数

typedef void(*Pfunction)(void);  定义一个无参无返回值函数指针

Pfunction pf;

pf=(Punfction)  *((int*)(*(int*)&base)+0);

pf();执行

1、单继承无函数覆盖(打印Sub对象的虚函数表) :在虚函数表中得出6个虚函数地址

struct Base

{

public:

    virtual void Function_1()     

{

        printf("Base:Function_1...\n");     

}

    virtual void Function_2()

    {

        printf("Base:Function_2...\n");

    }

    virtual void Function_3()

    {

        printf("Base:Function_3...\n");

    }

};

struct Sub:Base

{

public:     virtual void Function_4()

    {

        printf("Sub:Function_4...\n");

    }

    virtual void Function_5()

    {

        printf("Sub:Function_5...\n");

    }

    virtual void Function_6()

    {

        printf("Sub:Function_6...\n");

    }

};

 红线部分为虚函数表地址

红框中为虚函数表中 虚函数的地址

2、单继承有函数覆盖(打印Sub对象的虚函数表):在虚函数表中得出只有4个虚函数地址,编译器会自动把重复的函数(名字参数返回值都一样的函数) 定义成同一个地址

struct Base

{

public:     virtual void Function_1()

    {

        printf("Base:Function_1...\n");

    }

    virtual void Function_2()

    {

        printf("Base:Function_2...\n");

    }

    virtual void Function_3()

    {

        printf("Base:Function_3...\n");

    }

};

struct Sub:Base

{

public:     virtual void Function_1()

    {

        printf("Sub:Function_1...\n");

    }

    virtual void Function_2()

    {

        printf("Sub:Function_2...\n");

    }

    virtual void Function_6()

    {

        printf("Sub:Function_6...\n");

    }

};

只有virtual函数是动态绑定,动态绑定还有一个别名:多态。

动态绑定:当函数被重写(多继承时被相同名字相同返回值相同参数的函数覆盖),那么你当前调用的哪个结构体指针,它的虚表中的重写函数的地址,就会默认是该结构体内的虚函数地址(如果是个子类,那么会覆盖父类的地址  ):

即两个相同的函数,调用的哪个结构体指针,执行时,就会调用当前结构体内的虚函数,而覆盖掉其它子类或父类的相同函数 ,父类一样名字的虚函数(参数与返回值也相同),会被覆盖不被执行.

而当用父类指针时,子类中一样名字(参数与返回值也相同)的虚函数,会被覆盖不执行。.

总结就是:虚函数在有函数覆盖的情况下,用的哪个结构指针,虚函数表中的虚函数地址就会默认是当前结构内的虚函数

非虚函数被覆盖时,在调用时,编译的时候是写的父类的函数地址,子类的会被覆盖。

在多继承时,析构函数需要定义为虚函数.以防它只调用父类的析构函数。

动态绑定是通过虚表来实现的。

多态==动态绑定

前期绑定则是在编译的时候 就把call的地址固定了的直接调用

动态绑定 则是通过虚表间接调用,执行的时候 才会绑定对应的地址

多态实际应用很少,多半是看别人用了相关代码时 能知道别人到底调用的哪个函数.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值