什么是多态?

描述

什么是多态?

父类指针即根据指向的不同对象,响应同一消息(函数调用),产生不同行为。

多态三要素?

1,继承

2,虚函数重写

3,父类指针(引用)指向子类对象

多态的实现很简答,让我们来看一段代码

#include
using namespace std;
class Parent
{
public:
  virtual void show()
{
    cout << "我是你爹" << endl;
  }
};
class Child:public Parent//1,继承
{
public:
  virtual void show()//2,虚函数重写
{
    cout << "我是你崽" << endl;
  }
};


int main()
{
  Parent *pa = new Child;//3,父类指针指向子类对象
  pa->show();


  getchar();
  return 0;
}
//结果输出的是子类的show函数--"我是你崽"

实现很简单,但是这又是什么原理呢?

当我们在类中声明了虚函数之后,编译器会给类添加一个vptr指针,当定义对象的时候,会把所有虚函数放入一个叫虚函数表的顺序表,然后用vptr指针指向虚函数表。当进行pa->show();调用的时候,C++编译器不需要区分子类或者父类对象,只需要在pa指针中,找到vptr指针即可。

如果对象类型是子类,就调用子类的函数;如果对象类型是父类,就调用父类的函数,(即指向父类调父类,指向子类调子类)此为多态的表现。

既然类里面有vptr指针,那么我们能找到它吗?

咱们一起来探究下:首先看下加了虚函数的类的大小有没有变化。

函数调用

可以看到加了虚函数,类的大小比没有增加虚函数的类,多了四个字节的空间,有的同学可能会说,四个字节的类型不一定是指针。不要着急,让我们继续往下看。

接下来我们定义对象,然后通过调试,看下局部变量窗口

函数调用

从这里就可以明确看到,子类对象中有一个vptr指针,而且它是对象的第一个成员,它的类型是void**,指向的是一个顺序表,下标为0的元素装的是我们声明的虚函数。

那么,知道了这些,咱们能利用对象找到虚函数表,然后自己手动调用虚函数吗?

你们:肯定可以啊,废话

我:。。。那就废话不多说,欧力给!搞起

我:首先画一张内存模型图,瞅瞅(画工太丑,见谅)

函数调用

1,首先,要拿到vptr指针,怎么拿呢?因为它在对象的第一个元素,所以我们先对对象取地址&ch,这样就拿到了对象的地址。对象的元素的内存是连续的,但是现在指针的步长是Child类的大小,我们需要把它当成一个整型数组(因为vptr是四个字节),所以需要强转成int*,即(int*)&ch,这样之后数组第一个元素就是vptr指针了,取值即可得到

(int )&ch

2,然后,前面通过调试我们知道了,vptr指针是void**类型的,所以我们也要讲它转为int*,然后取值. (int )( (int )&ch),这样就拿到了虚函数表的第一个元素。

3,但是,现在拿到的元素是int*型,不是函数指针,无法调用,所以我们需要强转为函数指针,才能进行调用。

函数调用

你学废了没?嘿嘿

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分