本篇文章就来探索多态的原理。
先看下面的类
class Animal
{
public:
void speak()
{
cout << "动物在说话" << endl;
}
void eat()
{
cout << "动物在吃饭" << endl;
}
};
用vs2013开发人员命令工具.exe输入,如下命令,先来看一下编译后Aninmal的结构
cl /d1 reportSingleClassLayoutAnimal test.cpp
编译后的Animal的结构如下

可以发现什么都没有,这是正常的,因为普通函数它并不会存在于类中,那么好现在就给speak()加1个virtual关键字
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
void eat()
{
cout << "动物在吃饭" << endl;
}
};
继续输入如下命令,查看编译后的类结构
cl /d1 reportSingleClassLayoutAnimal test.cpp
打印结果如下

可以发现,加了virtual之后,Animal类就会增加一个vfptr的指针,该指针指向一个vftable,在vftable里有Animal的speak()的函数地址。目前为止,我们明白了virtual的作用就是将函数放到vftable所指向的表里。
讲了这么多,还没到多态,别着急,原理总是要一步一步推敲出来的,
此时,再让Cat类继承于Animal,如下
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
void eat()
{
cout << "小猫在吃鱼" << endl;
}
};
那么我们再看一下Cat编译之后的类结构

你可以发现一个有趣的现象,就是Cat没有virtual修饰的函数,为什么它还有vftable?
真实原因是这样:Cat 继承于Animal ,所以Cat同样会把virtual 对应的speak()也继承下来,因此Cat也会有vftable,
但继承后,编译器发现Cat也有一个speak(),所以编译器就自动的将&Animal::speak()替换成了&Cat::speak(),这种情况在其他编程语言里也叫做重写。
此时在来看如下代码
Animal * animal = new Cat;
animal->speak();
在编译时,Cat的vfptr的地址指向的是Animal的vftable,而在运行时,执行new Cat()时,在构造函数里,会将Cat对象的vfptr指向自己的vftable,因此在调用speak()时,就会去自己的vftable里找,这样就实现了多态的调用。

906

被折叠的 条评论
为什么被折叠?



