1、 概念
首先,什么是绑定?( what`s the definition of binding? )
c++编程思想上有说到:
Connecting a function call to a function body is called binding.(将函数体和函数调用关联起来,就叫绑定)
然后,那么什么是早绑定?(Early binding)
When binding is performed before the program is run (by the compiler and linker), it' s called early binding
在程序运行之前(也就是编译和链接时),执行的绑定是早绑定。
然后,什么是迟绑定?(late binding)
late binding, which means the binding occurs at runtime, based on the type of the object.
When a language implements late binding, there must be some mechanism to determine the
type of the object at runtime and call the appropriate member function
迟绑定发生在运行时,基于不同类型的对象。当一种语言实现迟绑定时,必须有某种机制确定对象的具体类型然后调用合适的成员函数。
2、 结论
2.1对于含有虚拟函数的类来说:
Ø 虚函数表是与类关联的,也就是说,一个类只有一张虚函数表。(从这个方面上说,虚函数类似于类的静态函数)(父类有一个Vtable,子类也有一个Vtable)
Ø VTable中虚函数的位置是由基类决定的,所以,哪怕你在派生类中不是按基类的顺序来重写虚函数,派生类的VTable中虚函数的存放顺序和基类的也是一样的。
Ø 虚函数指针VPtr是与对象关联的,每个对象都有一个虚函数指针,但是,同类的对象的虚函数指针的值是相同的。因为都指向该类的虚函数表。
Ø 虚函数指针VPtr的值是在调用构造函数时进行初始化的(自动完成)。
2.2 C++迟绑定实现机理流程(编译器都是类似于此种方式实现的):
(1)为每个含有虚函数的类(基类以及派生类)都创建一张虚函数表(VTable,存储于常量区),依次存放虚函数的地址。对于派生类来说,如果没有重写其基类的虚函数,那么,将会在VTable中存放基类的虚函数地址。
(2)为每个含有虚函数的类的对象,创建一个指针(VPtr),指向这个类的虚函数表(所以说,同类对象的VPtr的值是一样的[*VPtr相同,但VPtr不同],也就是说,虚函数,在这一点上,类似于类的static函数,是所有对象共有的。)(此过程发生在运行期自动调用构造函数的过程中)
(3)通过强制转换将派生类对象的地址/引用 赋给基类指针/变量(也就是向上类型转换UpCasting)(此步决定了基类指针首先寻址的虚函数表,也就是现在派生类的虚函数表中寻址,如果在派生类的虚函数表中没有找到此虚函数,则向上一级基类的虚函数表中寻找此虚函数,依次类推。由此可见,虽然代码相同,却实现了调用不同类函数的目的,也就是多态)
(4)然后,通过基类指针/引用对象 来调用虚函数(即:polymorphic call),就会通过此时基类对象的VPtr指针在所指向虚函数表中寻址(一般是从表头地址开始,加上一定的偏移量)找到相应的函数地址,也就是之前派生类VPtr指针指向的虚函数表的函数地址。
2.3晚绑定原理
编译器对每个包含虚函数的类创建一个表(称为V TA B L E)。在V TA B L E中,编译器放置特定类的虚函数地址。在每个带有虚函数的类中,编译器秘密地置一指针,称为v p o i n t e r(缩写为V P T R),指向这个对象的V TA B L E。通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生。为每个类设置V TA B L E(编译期)、初始化V P T R(运行期构造函数中)、为虚函数调用插入代码(运行期多态调用时),所有这些都是自动发生的,所以我们不必担心这些。利用虚函数,这个对象的合适的函数就能被调用,哪怕在编译器还不知道这个对象的特定类型的情况下。(《C++编程思想》)
2.4早绑定和晚绑定优缺点
早绑定,晚绑定,早晚都要绑定。绑定指在对象和其类型间建立关联的过程。
早绑定指在对象申明的时候就和他的类型建立了关联。
晚绑定是指我们的代码在运行时再检查对象是否提供了我们所需要的方法和属性。
很多人说C#和Java是早绑定的,javascript,python是迟绑定的,其实这个说法并不全对
一方面,C#和Java是强类型的,在变量声明的时候就说明了类型,从这里来讲当然是早绑定的,于是我们才能在IDE中享受代码提示带来的方便,因为ide通过你的申明就能知道你的对象是什么类型,具有什么方法和属性,然后提示给你,同时编译的时候也可以帮你检查许多类型转换的错误.
另一方面:无论C#和Java在实现他们很重要的一个功能:多态的时候,都是用晚绑定,比如你的父类中定义了virtual的方法,那么这个方法可能会在你的子类中重载,具体你用什么子类,是变量申明时所不知道的,在C++编译器会在编译的时候为这些类加上一个指针,指针指向一个虚表,虚表中存在着真实的函数,这个是就是一个晚绑定了
早绑定的优点是:
Ø 编译效率
Ø 代码提示(代码智能感知)
Ø 编译时类型检查
晚绑定的优点是:
Ø 不用申明类型
Ø 对象类型可以随时更改
参考资料:
http://blog.csdn.net/faithmy509/archive/2009/05/21/4207625.aspx
http://www.cnblogs.com/yizhu2000/archive/2007/07/12/815628.html