时光荏苒,又到了该找工作的时间了。对于找软件开发相关职位的同学们来说,复习好牢固的基础知识很重要!最近面了几家公司的c++工程师(面试结果暂且不论),他们都有问c++多态性的实现机制是如何?我就专门抽时间就这个知识点进行梳理。希望对找工作的同学们有所帮助!
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们都知道c++是面向对象的编程语言,多态性是很重要的一个特点!那么在c++中多态性具体是怎么体现的呢?
首先,c++中多态的实现宏观来讲分为两个方面:
(1)、静态多态
(2)、动态多态
1、静态多态:
很多同学可能对静态的多态感觉很陌生,我换个说法你就熟悉了。所谓静态的多态是说在编译器编译过程中就确定了该执行什么内容的一种实现,就技术来讲就是函数重载!
函数重载大家都很熟悉吧,所谓函数重载就是使用了相同函数名不同函数列表的函数(不包括返回类型)。
//举个函数重载的例子
(1) double caculate(double);
(2) double caculate(double,double);
(3) double caculate(double,int);
(4) double caculate(int,double);
(5) double caculate (int);
(6) double caculate(float);
(7) float caculate(double)
以上7个函数,(1)(2)(3)(4)(5)(6)中任意两个都能构成重载,(6)(7)也可以构成重载。但是,(1)(7)构不成重载,因为(1)(7)函数列表参数相同(不包含返回类型)
2、动态多态:
所谓动态多态是在函数运行期间根据具体的类型动态执行对应操作的实现,是c++多态性实现的重要技术。多态性主要用在包含继承类的体系中。
动态多态依赖于虚函数的实现,所谓虚函数是指在类中用virtual关键字标识的成员函数。对于虚函数来讲,可以在继承类中对父亲类中的虚函数进行重载的(要求函数参数列表完全一致)。
在用基类对象的指针或者引用调用该成员函数时就会进行运行时判断,根据调用对象实际的类型在虚函数表中查找对应的虚函数表执行对应的函数实现多态!
// ConsoleApplication20.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
class Father
{
public:
virtual void fun()
{
cout << "I am father!" << endl;
}
};
class Son :public Father
{
public:
void fun()
{
cout << "I am son!" << endl;
}
};
int main()
{
Son son;
Father *Pfather = &son;
Father& father = son;
Pfather->fun();
father.fun();
Father fath;
Father* Pfath = &fath;
Pfath->fun();
system("pause");
return 0;
}
在这个实现机制下,发生了什么?
当我们将函数声明为virtual 时,编译器不会在编译时就确定对象要调用的函数的地址,而是在运行时再去确定要调用的函数的地址,这就是晚绑定,也叫做动态绑定。
第一:编译器在发现Father 类中有虚函数时,会自动为每个含有虚函数的类生成一份虚函数表,也叫做虚表,该表是一个一维数组,虚表里保存了虚函数的入口地址。
第二:编译器会在每个对象的前四个字节中保存一个虚表指针,即(vptr),指向对象所属类的虚表。在程序运行时的合适时机,根据对象的类型去初始化vptr,从而让vptr指向正确的虚表,从而在调用虚函数时,能找到正确的函数。
第三:所谓的合适时机,在派生类定义对象时,程序运行会自动调用构造函数,在构造函数中创建虚表并对虚表初始化。在构造子类对象时,会先调用父类的构造函数,此时,编译器只“看到了”父类,并为父类对象初始化虚表指针,令它指向父类的虚表;当调用子类的构造函数时,为子类对象初始化虚表指针,令它指向子类的虚表。
总结:
(1)C++的多态性是通过晚绑定(动态绑定)技术实现的。
(2)含有虚函数的类都有虚表。
(3)当子类对父类的虚函数没有重写时,子类的虚表指针保存的是父类的虚表;当子类对父类的虚函数重写时,子类的虚表指针保存的是子类的虚表;当子类中有自己的虚函数时,在虚表中将此虚函数地址添加在后面。
c++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数。
还可以参考下:https://blog.csdn.net/qq_39412582/article/details/81628254