定义一个类:
class Animal
{
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
类内只有一个非静态的成员函数,这个函数并不属于类的对象(分开存储),相当于一个空类。此时打印类的占用空间大小,发现占用内存为1.(即空类大小为1)
void test02()
{
cout << sizeof(Animal) << endl;//结果为1
}
接下来在这个成员函数前加上virtual关键字,再次打印类占用内存大小,发现结果为4.
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
void test02()
{
cout << sizeof(Animal) << endl;//结果为4
}
这是为什么呢?接下来先介绍一个东西:vfptr
v即virtual
f即function
ptr即pointer
合起来即virtual function pointer,即虚函数指针
这个指针会指向一个虚函数表。
在之前的Animal类中我们定义了虚函数:
virtual void speak()
{
cout << "动物在说话" << endl;
}
此虚函数会有一个地址,取地址:&Animal::speak
(即Animal类中的speak函数的地址)
这个地址会放在vftable中,即虚函数表中。
指针vfptr指向这个虚函数表:
我们定义了cat类,并继承了Animal类,此时cat类中的虚函数表中继承了animal类中的一切:
然后在cat子类中,我们重写了Animal父类的虚函数:
void speak()
{
cout << "小猫说话喵喵喵" << endl;
}
当子类重写父类的虚函数,子类中的虚函数表内部会将继承的父类虚函数表替换成(即覆盖)子类的虚函数地址(父类中的表不变化,只是子类把自己继承的给换了):
当父类的指针或引用指向子类对象时候,就发生了多态。
doSpeak函数中调用的是animal类(父类)中的speak函数:
void doSpeak(Animal& animal)//Animal &animal = cat
{
animal.speak();
}
当你创建cat对象,并把cat对象传给这个父类speak函数:
Cat cat;
doSpeak(cat);
此时指针指的是cat对象:Animal &animal = cat
那么函数调用时就从cat的虚函数表中找这个speak函数,调用cat自己的speak函数