多态
默认情况下,父类指针指向子类对象,只能调用父类中的函数。 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这个地址。 虚函数表
- 继承父类的 重写了,自己类的虚函数 没有重写,父类中的虚函数
- 自己类中新增的virtual
不同情况的虚函数表 父是父的虚函数表,子是子的虚函数表。不要混为一谈。 单继承:B继承A,C继承B。只有一张虚函数表。 多继承:C继承A,C继承B。有两张虚函数表,C中自己新增的放在先继承的表中。 菱形继承中顶层属性重复,用虚继承解决。子类会生成两张表;两个父类会生成一张表;爷爷类没有表。 虚继承中夹杂虚函数。子类最多有四张表。