C++的几种多态形式
从广义上来说,多态性是指一段程序能够处理多种类型对象的能力。在C++中,这种多态性可以通过重载多态(函数和运算符重载)、强制多态(类型强制转换)、类型参数化多态(模板)和包含多态(继承及虚函数)4种形式来实现。
重载、模板等多态形式,究竟调用函数哪个的具体实现,在编译阶段就已经确定,我们称前三种多态属于静态联编;而最后一种,即c++狭义上的多态,虚函数则属于动态联编,因为它的具体实现只能在程序运行时根据对象的实际类型确定。
联编
联编(binding)又称绑定,当我们使用程序调用函数的时候,究竟应该执行函数对应的哪一个代码块呢?将源代码中的函数调用解释为执行特定的函数代码块这个过程被称为函数名联编。
知识扩展:c和c++编译阶段对调用函数的编译处理以及符号表。
静态联编/绑定
在编译阶段就将函数实现和函数调用绑定起来称为静态联编(static binding),又叫早期绑定。静态联编在编译阶段就必须了解所有的函数或模块执行所需要的信息。在C语言中,所有的联编都是静态联编;在C++中,一般情况下联编也是静态联编。
不过上面这句话“在C语言中,所有的联编都是静态联编”这里要暂时打个问号,这句话是教科书原话。但是个人理解c的回调函数也属于动态联编,CSDN的chatgpt也可以举证。。。
如下,以c++的重载为例。main函数中的几个func调用,c++编译器完全可以很明确每个func调用具体去执行哪个实现的。因为,c++在编译阶段,会通过函数名+函数的参数形式 唯一确定一个函数实现。
//函数重载需要函数都在同一个作用域下 void func(int a) { cout << "func (int a) 的调用!" << endl; } void func(double a) { cout << "func (double a)的调用!" << endl; } void func(int a ,double b) { cout << "func (int a ,double b) 的调用!" << endl; } int main() { func(10); func(3.14); func(10,3.14); system("pause"); return 0; }
动态联编
动态联编也称为晚期绑定,是指在运行时根据对象的类型确定方法调用的具体实现。有时候方法调用者和其调用方法之间不是完全确定的,可能需要依赖程序运行起来以后,根据调用者的类型或者传参情况才能把具体实现终于确定下来。
举个多态虚函数的例子,理解为什么需要动态联编。如下,一个含虚函数的基类animal,两个派生出来的 类cat和dog。我们在不“运行”代码的情况下,同编译器的视角看这段代码。
当test01方法调用起来后,紧接着里面第一个DoSpeak()调用,显然DoSpeak()里面要执行一个函数调用speak。那么要具体执行sepak的那个实现呢?这个要依赖函数运行起来之后,传入DoSpeak的实参决定,传入cat对象就执行cat的虚函数。也就是说,只有程序运行起来,DoSpeak传入实参,才能确定(绑定)speak的具体实现。
class Animal { public: //Speak函数就是虚函数 //函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。 virtual void speak() { cout << "动物在说话" << endl; } }; class Cat :public Animal { public: virtual void speak()//子类的函数前面不加virtual 也可以重写,但是不规范不建议。 { cout << "小猫在说话" << endl; } }; class Dog :public Animal { public: virtual void speak() { cout << "小狗在说话" << endl; } }; //我们希望调用什么对象中的函数,那么就传入什么对象 //如果函数地址在编译阶段就能确定,那么静态联编 //如果函数地址在运行阶段才能确定,就是动态联编 void DoSpeak(Animal & animal)//注意函数形参 { //多态使用: animal.speak(); //父类指针或引用指向子类对象 } void test01() { Cat cat; DoSpeak(cat); Dog dog; DoSpeak(dog); } int main() { test01(); system("pause"); return 0; }
静态/动态联编 与 静态/链接链接 概念辨析
两组概念之间没啥关系,说的不是一个事儿
静态链接
在编译成可是执行文件时,自动链接依赖的目标库,如果需要多次链接相同的目标文件,则需要对于目标文件进行多次的拷贝动态链接
在程序运行时,每次需要连接依赖的动态链接库时,才会连接动态链接库,且改目标文件只有一份拷贝。
参考:
C++静态绑定、动态绑定;静态编译、动态编译;静态链接、动态链接;静态联编、静态联编_c++ 编译 函数绑定 流程_爱学习滴好青年的博客-CSDN博客
C++动态联编介绍-CSDN博客