C++进阶(五) : 多态【详解】

1、 什么是多态

在面向对象中,多态(动态多态)是指基类指针或引用指向子类对象,在运行时根据基类的引用(指针)的指向内容动态调用实际绑定对象函数的行为

与之相对应的是静态多态,静态多态编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数就调用,没有的话就会发出警告或者报错,如函数重载,非虚函数重写等。

多态是设计模式/软件框架的基础。

C++进阶(五) : 多态【详解】_第1张图片

 2、多态的条件

  1. 有继承
  2. 有虚函数重写(被 virtual 声明的函数叫虚函数)
  3. 有父类指针(引用)指向子类对象

3、多态的实现原理

当类中声明了虚函数时,编译器就会为该类生成一张虚函数表,且由编译器自己维护,里面存储的是该类的所有虚(virtual)成员函数。

之后当我们用这个类创建对象时,就会在对象中产生一个 vptr指针(虚函数指针),存储在实例对象内存的最前面的位置,这个vptr指针指向的就是该类的虚函数表。

在多态函数调用时, 实例对象会通过vptr指针到该类的虚函数表中查找实际应被调用的函数,从而找到正确的函数入口地址。

C++进阶(五) : 多态【详解】_第2张图片

C++进阶(五) : 多态【详解】_第3张图片

C++进阶(五) : 多态【详解】_第4张图片

C++进阶(五) : 多态【详解】_第5张图片

 注:出于效率考虑,没有必要将所有成员函数都声明为虚函数。

当父子类都含有虚函数时:

  1. 子类会将父类的虚函数表拷贝一份。
  2. 父类虚函数未被覆盖时,虚函数表中该位置内容不变,依然是父类到虚函数地址。
  3. 父类虚函数被覆盖时,虚函数表中该位置内容呗替换为子类的虚函数地址。
  4. 多继承时,子类会包含多个虚函数表以及虚函数表指针,分别指向从不同父类拷贝来的虚函数表内容

 4、虚函数知识点问答 

1. 构造函数可以成为虚函数吗?

不可以。因为父类对象会在子类之前进行构造,此时子类部分的数据成员还未初始化, 因此调用子类的虚函数是不安全的,故而C++不会进行动态联编。

2. 析构函数可以成为虚函数吗?

可以,并且产生动态多态。因为析构函数是在对象销毁之前被调用,即在对象销毁前  虚函数表指针是正确指向对应的虚函数表。且建议将析构函数声明为虚构函数的,因为虚析构函数可以指引 delete 运算符正确析构动态对象,即当父类指针指向子类对象时,通过父类指针去释放所有子类的内存空间,避免内存泄露。

3. 构造函数中可以调用虚函数发生多态吗?

构造函数中可以调用虚函数,但是不可能发生多态行为,因为在构造函数执行时,虚函数表指针可能未被正确初始化。

4. 析构函数中可以调用虚函数发生多态吗?

析构函数是用来销毁一个对象的,在销毁一个对象时,先调用子类的析构函数,然后再调用基类的析构函数。所以在调用基类的析构函数时,派生类对象的数据成员已经“销毁”,这个时再调用子类的虚函数已经没有意义了。

你可能感兴趣的:(C++进阶,c++,asp.net,c#)