虚函数表,静态、动态联编

虚函数表:

在基类中的成员函数为虚函数后,会在基类内存前会存储指向虚函数表的指针,指针中存放着虚函数的地址(为一段动态数组存储)。当派生类继承基类后,虚函数表也会被添加到派生类中,对基类的虚函数进行重写后,虚函数表中对该函数的指针也改变,当派生类中的基类对象再指向函数时,就会指向替换过的派生类中重载的同名函数。

静态编译:

   记录类的属性、函数。可访问属性、默认参数。编译时就要确定类型的属性方法,属性的可访问性,类型。 函数的名称、可访问性、形参。

 动态联编:地址晚绑定,运行时绑定好地址

多态原理解析:

1.当父类中有了虚函数后,内部结构就发生了改变。

2.内部多了一个vfptr。virtual function pointer 虚函数表指针。  指向vftable 虚函数表

3.父类结构 vfptr &Animal::speak

4.子类中进行集成会继承 vfptr vftable

5.构造函数中会将虚函数表指针 指向自己的虚函数表

6.如果发生了重写,会替换掉虚函数表中的原有的speak,改为&Cat::speak

7.深入剖析,内部到底如何调用。

8.(void(*)()) (*((int*)*(int*)animal)) ()

9.猫吃鱼的函数调用(编译器)

构造和析构函数中进行静态联编,不使用虚函数表。因为在这两个过程中,我们是设置和重置虚函数表指针,与静态联编使用的函数过程相同,为了保证效率。

10.虚表指针的初始化是在构造函数的过程中,进行初始化的。先构造基类对象时,先调用基类的构造函数,此时虚表指针指向为基类的虚表。之后进入派生类的构造函数,再讲虚表指针初始化为派生类虚表指针。

11.在派生类对象对基类对象赋值时,并不能将虚表指针一并赋值。比如

class Object
{
   public:
    virtual void fun() {}
    virtual void add() {}
};
class Base:public Object
{
int value;
   public:
     virtual void fun()  {cout<<value+=10<<endl;}
     virtual void add() {}


};
int main()
{
    Object* op=(Object*)malloc(sizeof(Object));
    Object obj;
    
    Object  *op=&obj;
   Base base;
obj=base;   //如果将base对象中的obj赋值给obj对象时,如果虚表指针一同被复制到obj中去,
//在引用fun时,就会对Base的虚表进行访问,此时的Base::fun函数会调用value 值进行操作,
//但是obj中并没有Base类对象的value值可供调用。此时被赋值的obj的虚表指针为随机值。
//不应该将*op=obj;然后再进行对op的使用
new(op) Object(10);
op->fun();
}

 注意:构造函数不能为虚函数,为什么?

1.构造函数的用途:1)创建对象,2)初始化对象中的属性,3)类型转换。

2.在类中定义了虚函数就会有一个虚函数表(vftable),对象模型中就含有一个指向虚表的指针。(_vfptr)。在定义对象时,构造函数设置虚表指针指向虚函数表。

3.使用指针和引用调用虚函数,在编译只需要知道函数的接口,运行时指向具体对象,才能关联具体对象的虚方法(通过虚函数指针查虚函数表得到具体对象中的虚方法)

4.构造函数是类的一个特殊的成员函数:

 1)定义对象由系统自动调用构造函数,对象自己是不可以调用构造函数;

2)构造函数的调用属于静态联编,在编译时必须知道具体的类型信息。

5.如果构造函数可以定义为虚构造函数,使用指针调用虚构造函数,如果编译器采用静态联编,构造函数就不能为虚函数。如果采用动态联编,运行时指针指向具体对象,使用指针调用构造函数,相当于已经实例化的对象再调用构造函数,这是不容许的调用,对象的构造函数只执行一次。

6.如果指针可以调用虚构造函数,通过查虚函数表,调动虚构造函数,那么,当指针为nullptr,如何查虚函数表呢?

7.构造函数的调用是在编译时确定,如果是虚构造函数,编译器怎么知道你想构建是继承树上的哪种类型呢?

虚析构函数:当基类中有虚函数时,需要设计虚析构函数,因为如果派生类中的构造函数中申请使用了动态资源,当以基类指针指向派生类对象时,如果析构函数不为虚函数,在根据指向派生类对象的基类指针释放资源,调用析构函数时,就会调用基类的虚构函数,派生类析构函数将不会调用,此时派生类对象申请的动态资源将不会被释放,造成内存泄露。

设计原则:如果基类中没有虚函数,则不需要派生出子类型,有虚才有继承。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值