汇编分析多态 虚函数表

多态

    默认情况下,父类指针指向子类对象,只能调用父类中的函数。 Animal *p = new Dog指针p只能调用Animal类中的函数
#include <iostream>
using namespace std;

class Animal {
          
   
public:
	int m_age;
	void speak() {
          
   
		cout << "animal speak()" << endl;
	}
	void run() {
          
   
		cout << "animal run()" << endl;
	}
};

class Cat:public Animal {
          
   
public:
	int m_live;
	void speak() {
          
   
		cout << "cat speak()" << endl;
	}
	void run() {
          
   
		cout << "cat run()" << endl;
	}
};

class Dog :public Animal{
          
   
public:
	void speak() {
          
   
		cout << "dog speak()" << endl;
	}
	void run() {
          
   
		cout << "dog run()" << endl;
	}
};


int main() {
          
   
	Animal* p = new Dog();
	p->run();
	p->speak();
/*
写死了,指针类型确定调用对应类型函数的类型.与对象类型无关
	p->run();
006B65F2  mov         ecx,dword ptr [p]  
006B65F5  call        Animal::run (06B1532h)  
	p->speak();
006B65FA  mov         ecx,dword ptr [p]  
006B65FD  call        Animal::speak (06B1505h)  

*/

	cout << "-------------" << endl;
	Cat* p1 = (Cat *)new Dog();
	p1->run();
	p1->speak();
	p1->run();
/*
	p1->run();
006B6665  mov         ecx,dword ptr [p1]  
006B6668  call        Cat::run (06B1541h)  
	p1->speak();
006B666D  mov         ecx,dword ptr [p1]  
006B6670  call        Cat::speak (06B153Ch) 
*/
	return 0;
}

多态的实现

Animal* p1 = new Cat();
	
	p1->speak();
	//函数调用与虚函数表有关,进而与虚函数指针有关,虚函数指针在对象中。 --> 函数调用与对象有关
	
	//eax 为Cat 对象的地址;p1指针指向对象,存放对象的地址
 mov         eax,dword ptr [p1]  
 	//edx 为虚函数指针;对象中前4个字节为虚函数指针的地址
 mov         edx,dword ptr [eax]  
 	//eax 为speak的函数地址
 mov         eax,dword ptr [edx]  
 call        eax  
   
	p1->run();
	//[ebp-8] 为对象的地址并没有写死,不同的对象地址不同
	//运行时多态 
 mov         eax,dword ptr [ebp-8] 
 mov         edx,dword ptr [eax]  
 	//eax为run的函数地址 
 mov         eax,dword ptr [edx+4]  
 call        eax

多态与重载

//多态,根据父类指针指向不同的对象,调用不同的函数。
//与对象类型有关
void fun(Animal *p){
          
   
	p->speak();
}

//重载:根据函数的参数不同调用不同的函数
//与指针类型有关
void fun(Animal *p){
          
   
	p->speak();
}
void fun(Cat *p){
          
   
	p->speak();
}

总结

    多态的要素 子类重写父类的成员函数(override) 父类指针指向子类对象 利用父类指针调用重写的成员函数 多态 同一操作作用与不同对象,可以有不同的解释,产生不同的结果。 父类指针指向子类对象。多态:函数调用与子类对象类型有关;非多态:函数调用与父类指针类型有关。 将指针存放的地址给eax(对象的地址),取出对应的虚函数指针给edx(对象的前四个字节),根据虚函数的不同计算不同的偏移[edx+4] ,最后call这个地址。 虚函数表
  1. 继承父类的 重写了,自己类的虚函数 没有重写,父类中的虚函数
  2. 自己类中新增的virtual
    不同情况的虚函数表 父是父的虚函数表,子是子的虚函数表。不要混为一谈。 单继承:B继承A,C继承B。只有一张虚函数表。 多继承:C继承A,C继承B。有两张虚函数表,C中自己新增的放在先继承的表中。 菱形继承中顶层属性重复,用虚继承解决。子类会生成两张表;两个父类会生成一张表;爷爷类没有表。 虚继承中夹杂虚函数。子类最多有四张表。
经验分享 程序员 微信小程序 职场和发展