实验环境:Windows 10 + VS 2013
通过虚函数可以实现多态,代码如下:
1 #include <iostream> 2 using namespace std; 3 4 class A { 5 public: 6 virtual void display() { 7 cout << "This is A" << endl; 8 } 9 virtual void display2() { 10 cout << "This is A2" << endl; 11 } 12 13 private: 14 int _x; 15 }; 16 17 class B : public A { 18 public: 19 virtual void display() { 20 cout << "This is B" << endl; 21 } 22 virtual void display2() { 23 cout << "This is B2" << endl; 24 } 25 26 private: 27 int _y; 28 }; 29 30 void display(A& a) { 31 a.display(); 32 a.display2(); 33 } 34 35 int main(int argc, char** argv) { 36 37 A a; 38 B b; 39 40 display(a); 41 display(b); 42 43 return 0; 44 }
程序运行结果:
分析第40行和41行代内部执行过程:
main函数的汇编代码如下:
其中 ebp-0x10 是 a 的地址, ebp-0x24 是 b 的地址。可以看到 a 和 b 调用display的代码一样,但是调用 display 前都将自己的地址(也是this指针)存到了eax寄存器,然后作为参数压入stack中。跳到display函数中看看:
从上面图中可以看出,在非成员函数的display里面调用了成员函数display和display2。调用方式是通过虚表指针来调用的。this指针指向的是虚表指针,通过虚表指针找到虚函数表,然后再调用真正的display。
因为子类和父类的虚函数表不同,所以不同类型的的class的虚表指针指向不同虚函数表。所以即使非成员函数display的参数是一个A类型(父类)的引用,但是B(子类)在调用时也能正确的执行想要的操作。