汇编分析多态 虚函数表

多态

  • 默认情况下,父类指针指向子类对象,只能调用父类中的函数。
     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中自己新增的放在先继承的表中。
     菱形继承中顶层属性重复,用虚继承解决。子类会生成两张表;两个父类会生成一张表;爷爷类没有表。
     虚继承中夹杂虚函数。子类最多有四张表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值