前面我写了几篇关于继承的博文,分别为:
c++继承详解之一——继承的三种方式、派生类的对象模型
C++继承详解之二——派生类成员函数详解(函数隐藏、构造函数与兼容覆盖规则)
C++继承详解之三——菱形继承+虚继承内存对象模型详解vbptr(1)
C++继承详解之四——is-a接口继承和has-a实现继承
这几篇博文只涉及到了继承的知识,没有加入虚函数没有涉及到多态的知识,从这篇开始我会更新多态部分,后面会将继承和多态结合起来。
那么就开始多态篇~~~
首先,说起多态就必须要讲静态联编,动态联编。这俩也叫静态绑定和动态绑定。有些书比如C++ Primer也叫静态类型和动态类型。谭浩强写的C++程序设计直接叫静态多态性和动态多态性。
为什么说起多态就要先说他俩呢,首先,多态是什么?
以下参考百度百科~
多态(Polymorphism)按字面的意思就是“多种状态”。
在面向对象语言中,接口的多种不同的实现方式即为多态。
引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。
简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在Object Pascal和C++中都是通过虚函数(Virtual Function) 实现的。
上面的一段话讲得十分官方(哈哈),让我总结来说,多态就是一个事物有多种形态。
一、静态联编,动态联编,静态类型,动态类型
1.静态多态,动态多态
静态多态和动态多态的区别其实用下面的图就可以体现:
2.静态联编,动态联编
那么静态联编和动态联编分别是什么呢
首先我们先搞清楚联编是什么:
联编的作用是:程序调用函数,编译器决定使用哪个可执行代码块。
也就是确定调用的具体对象。
class A
{
public:
void Fun();
};
class B:public A
{
public:
void Fun();
};
int main()
{
B b;
b.Fun();
//上一行究竟调用A类的Fun()函数还是B类的Fun函数
//确定具体对象的过程叫做联编
return 0;
//这个例子只是让大家了解一下什么是联编
//关于这个例子中涉及的知识点,在后面会提及
}
正如上面所说的,联编的分类是根据进行阶段不同分类的。
静态联编其实就是类似上面我们提到的,函数重载和运算符重载,它是在编译过程汇总进行的联编,又称早期联编。
而动态联编是在程序运行过程中才动态的确定操作对象。
3.静态类型,动态类型
在C++Primer一书中,讲到了静态类型和动态类型。
静态类型和动态类型可用于变量或表达式。
表达式的静态类型在编译时总是已知的,它是在变量声明时的类型或表达式生成的类型。
动态类型则是变量或表达式表示的内存中的对象的类型,直到运行时才可知。
其实静态类型和动态类型与静态联编,动态联编是与指针和引用有着很大关系的。
原因如下:
实际上一个非指针非引用的变量,在声明时已经确定了它自己的类型,不会再后面改变。
而指针或引用可以进行类型转换的原因,就是下面要好好分析的。
下面我要问一些问题。
1.什么有两种类型的联编?
2.既然动态联编如此好,为什么不将他设置成默认的?
3.动态联编是如何工作的?
现在我对上面的问题解答一下。
为什么有两种类型的联编以及为什么默认为静态联编?
原因有两个——效率和概念模型。
1.效率
为了使程序能够在运行阶段进行决策,必须采取一些方法来跟踪基类指针或引用指向的对象类型,这增加了额外的处理开秀,所以,在派生类不需要重新定义基类方法的情况下,静态联编的效率更高。
2.内存和存取时间,这点在后面虚函数的介绍中会提及
二、指针和引用类型兼容性
在我以前的博文C++继承详解之二——派生类成员函数详解(函数