多态的实现原理刨析
虚函数关键字:virtual 未写virtual关键字前:
代码语言:javascript复制#include<iostream>
using namespace std;
class Animal {
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat :public Animal {
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
void test()
{
Animal* a = new Cat;
a->speak();
}
int main()
{
test();
system("pause");
return 0;
}
输出结果:
添加了virtual关键字后:
代码语言:javascript复制#include<iostream>
using namespace std;
class Animal {
public:
//虚函数
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat :public Animal {
public:
//这里的virtual可写可不写,因为继承至Animal,因此如国不写virtual,与父类里面speak同名的函数也会默认为虚函数
virtual void speak()
{
cout << "小猫在说话" << endl;
}
};
void test()
{
//多态发生条件:父类指针或者引用指向子类
Animal* a = new Cat;
a->speak();
}
int main()
{
test();
system("pause");
return 0;
}
输出结果:
区别: 代码本意是调用猫类里面的speak函数,但是未在父类speak函数前加virtual关键字时,调用的是父类的speak函数,加了virtual关键字后,调用的是猫类里面的speak函数,这就是多态
在深入探究多态实现原理前,先要理解多态的意思和虚函数实现的条件
多态: 不同类的对象对同一消息的不同响应 注意: 虚函数实现条件 : 1.有继承关系 2.子类重写父类的虚函数 动态多态的使用: 父类的指针或者引用指向子类的对象
多态实现的原理探究:
未写虚函数前:
代码语言:javascript复制#include<iostream>
using namespace std;
class Animal {
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat :public Animal {
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
void test()
{
Animal a;
cout << "空对象a的大小为" << sizeof(a) << endl;
}
int main()
{
test();
system("pause");
return 0;
}
写了虚函数后:
代码语言:javascript复制#include<iostream>
using namespace std;
class Animal {
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat :public Animal {
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
void test()
{
Animal a;
cout << "空对象a的大小为" << sizeof(a) << endl;
}
int main()
{
test();
system("pause");
return 0;
}
未写虚函数前,空对象a的大小为1,写了虚函数后,对象a的大小为4,是因为此时a里面存放了一个vfptr虚函数(表)指针,指针大小无论类型均为4个字节大小 该虚函数指针指向一个虚函数表
当子类未重写父类虚函数时(即cat类里面没有与animal类里面speak同名的函数):
当子类重写了父类虚函数时:
当发生虚函数重写时,子类会把自己的虚函数覆盖掉之前父类的虚函数 因此当父类的指针或者引用指向子类对象的时候,会发生多态,你传入的是cat对象,就去cat的虚函数表中找speak函数的入口地址