多态与虚函数

多态与虚函数详解

多态是什么

多态是什么

  • 多态的意思字面上理解就是一个函数名有多种形态或者说多种状态,我们可以根据需求使用对应的那种形态。
  • 多态在c++中分为静态多态动态多态
  • 静态多态,也可以说编译时多态,也就是在编译时就设计了多个状态,比如说模板函数重载都是在编译时就设计好的多态。
  • 对应的动态多态也就是运行时多态,是在程序运行时才产生的多态,是通过继承和虚函数来实现的,利用指针指向不同对象,进而使函数有不同的实现,这也是程序设计模式里最重要的技巧。

虚函数的实现机制

虚函数的实现

  • 在说明虚函数的实现机制前,需要先说明的是类继承虚函数实现多态的前提条件有三个子类继承父类父类有虚函数,子类对虚函数进行重写,父类指针指向子类对象,这样的话父类指针的虚函数才能在运行时动态绑定我们设定的子类对象里的函数,然后是虚函数的实现机制。
  • 虚函数是通过虚函数指针虚函数表实现的,一个包含有虚函数的类,当创建这个类对象的时候,除了它自身的字段以外,它的内存还会多一个四字节的指针,在VS上你可以通过调试模式看到这个指针vfptr是放在对象的最前面的,它指向一个指针数组,这个数组就是虚函数表,里面存放的指针指向对应的虚函数。当我们调用一个对象的虚函数时,它会先通过虚函数指针先找到这个类的虚函数表,在表里找到你需要的那个虚函数。值得一提的时,虚函数指针是属于类对象的,存放在对象空间里,而虚函数表是属于类的,也就是说同一个类的所有对象共享这个虚函数表,它是在编译的时候生成的,放在只读数据段,也就是常量区
  • 然后就是虚函数能做到多态的原因,首先是假设父类有一个虚函数A,子类重写了这个虚函数A,这两个函数都会在编译的时候存放在代码段里,而子类继承父类的同时,也会继承父类的虚函数表,只不过在父类的表里写的是父类虚函数A的地址,而子类改成了重写之后的虚函数A地址。所以当我们通过指向子类对象的父类指针去调用函数时,会先通过虚函数指针找到虚函数表,然后再虚函数表上找到对应的虚函数指针,只不过这个虚函数指针指向的不再是父类的那个 虚函数而是子类的,这就实现的多态。

虚函数调用是在编译时确定还是运行时确定的?如何确定调用哪个函数?

  • 运行时确定的,通过虚函数表查找对应的虚函数的地址,进而调用对应的函数

虚函数是存在类中还是类对象中(即是否共享虚表)?

  • 虚函数本身时存放在代码段中的,而虚函数指针是属于类对象的,在VS中我们创建一个包含虚函数的类对象是,可以用sizeof查看它的大小会发现比正常的大四个字节,就是虚函数指针,在调试模式中可以看到创建类对象的时候,会自动在类对象空间的起始地方生成一个虚函数指针VFPTR。而虚函数表是属于整个类的,也就是说同一个类的所有对象共享一个虚函数表,这个虚函数表是在编译的时候生成的,所以应该放在的是只读数据区,也就是常量区。这个在VS的调试模式下也可以观察到,比如我写一个带有虚函数的类,同时设置一个const 常量,创建类对象后中断,可以看到常量的地址和虚函数指针的地址只相差四个字节。

基类的析构函数不是虚函数会带来什么问题

  • 我们使用父类指针指向子类对象的时候,父类析构函数不是虚函数,在我们delete掉父类指针时,只会调用父类的析构函数,此时如果子类对象中有指针,则可能造成内存泄漏,而如果把父类的析构函数设置为虚函数,就会先调用子类的析构函数在调用父类的析构函数。

在(基类的)构造函数和析构函数中调用虚函数会怎么样

在父类的构造函数析构函数中调用虚函数

  • 在VS上试过,会调用父类的虚函数而不是子类的,这里是因为在编译时已经静态绑定了,并没有通过虚函数指针调用这个虚函数。
    是因为在编译时已经静态绑定了,并没有通过虚函数指针调用这个虚函数。
  • 语法上是没有问题的,但是如果我们使用父类指针指向子类对象,在父类的构造函数里调用虚函数时,会调用子类的虚函数,但是因为编译器是先对父类进行构造,在对子类进行构造,此时子类的特有成分还未初始化,如果虚函数使用到了这些成分则一定会出错;同理子类先进行析构,然后父类析构时调用虚函数,但是子类已经被析构掉了,特有成分已经销毁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值