Objective
C + + is divided into compile-time polymorphic and Run-time polymorphism. Run-time polymorphism relies on virtual functions, and most people may have heard that virtual functions are implemented by virtual function tables + virtual function pointers, but are they really? Although the C + + specification has complex language details, the underlying implementation mechanism is left to the compiler manufacturer's imagination. (It is not possible that a particular processor circuit structure natively supports virtual functions, or that the processor is not a Vonneumann type at all, or that future manufacturers invent more efficient data structures than virtual function tables.) )
virtual function table
Encapsulation combines the data and operations of an instance, but the instance itself has only data, no functions, and functions of the same class are shared. We'll prove it indirectly by an example.
1 2 3 4 5 6 7 8 9 |
ClassBase1 { Public Inta Voidfunc () {cout << "heel" << Endl;} }; BASE1 B1; cout <<sizeof (B1) << Endl; |
Print
If a virtual function is in the class, a virtual function pointer is added to the object, which points to a virtual function table that is the address of each virtual function.
1 2 3 4 5 6 |
+--------+ +---------+ | pvtbl |------>| vfunc1 | +--------+ +---------+ | Data1 | | Vfunc2 | +--------+ +---------+ | ... | | ... | |
When a subclass inherits the parent class, it overwrites each item in the virtual function table in turn, and the item is retained if the subclass does not override an item. When an object is instantiated, the virtual function pointer exists as a hidden data in the instance. If normal member functions are invoked through the parent class pointer, because normal functions and types are bound together, the parent class member function is still invoked, and if a virtual function is invoked through the parent class pointer, the virtual function table (the virtual function table of subclasses) is found by the object's virtual pointer, and the virtual function item is positioned to achieve polymorphism.
The principle is not very simple? C + + is to implement advanced abstractions in this seemingly primitive way. This is the common practice of the compiler, as the Visual Studio 2013 compiler in my hand does, in order to improve performance, VS guarantees that virtual function pointers exist at the top of the object instance (and historically compilers do not do this, as if they were Borland?). )。
Implementation in Visual Studio 2013
Here's an example (this is because I know the memory layout of Visual Studio 2013 compiled objects)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include USINGNAMESPACESTD; Classbase { Public Typedefvoid (*func) (); Virtualvoidfunc1 () {cout << "base::func1" << Endl;} Virtualvoidfunc2 () {cout << "base::func2" << Endl;} Virtualvoidfunc3 () {cout << "base::func3" << Endl;} }; Classderived:publicbase { Public Virtualvoidfunc1 () {cout << "derived::func1" << Endl;} Virtualvoidfunc3 () {cout << "derived::func3" << Endl;} }; Intmain () { Base B, B1; int** pvirtualtable1 = (int**) &b; cout << "Base object VTBL Address:" << pvirtualtable1[0] << Endl; int** Pvirtualtable11 = (int**) &b1; cout << "Another Base object VTBL address:" << pvirtualtable11[0] << Endl; cout << "function in virtual table" << Endl; for (inti = 0; (Base::func) pvirtualtable1[0][i]!= NULL; ++i) { Auto P = (base::func) pvirtualtable1[0][i]; P (); } cout << Endl; Derived D; int** pvirtualtable2 = (int**) &d; cout << "Derived object VTBL Address:" << pvirtualtable2[0] << Endl; cout << "function in virtual table" << Endl; for (inti = 0; (Base::func) pvirtualtable2[0][i]!= NULL; ++i) { Auto P = (base::func) pvirtualtable2[0][i]; P (); } cout << Endl; } |
Print
1 2 3 4 5 6 7 8 9 10 11 12 |
Base Object Pvtbl address:0029da58 Another Base object Pvtbl address:0029da58 function Address invirtualtable Base::func1 Base::func2 Base::func3 Derived Object Pvtbl Address:0029db20 function Address invirtualtable Derived::func1 Base::func2 Derived::func3 |
As you can see, the virtual function tables for different instances of the same type are the same, and after inheriting, the subclasses have their own virtual function table, and the table has the corresponding update (DERIVED::FUNC1, derived::func3), and the items that are not overridden in the table remain the original value (BASE::FUNC2).