4.1 虚析构函数的必要性
将基类的析构函数声明为虚函数后,派生类的析构函数也会自动成为虚函数。这个时候编译器会忽略指针的类型,而根据指针的指向来选择函数;也就是说,指针指向哪个类的对象就调用哪个类的函数。pb、pd 都指向了派生类的对象,所以会调用派生类的析构函数,继而再调用基类的析构函数。如此一来也就解决了内存泄露的问题。
4.2 纯虚函数和抽象类
纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数。包含纯虚函数的类称为抽象类(Abstract Class)。之所以说它抽象,是因为它无法实例化,也就是无法创建对象。原因很明显,纯虚函数没有函数体,不是完整的函数,无法调用,也无法为其分配内存空间。抽象类通常是作为基类,让派生类去实现纯虚函数。派生类必须实现纯虚函数才能被实例化。
4.3 C++的虚函数表,多态的实现机制
如果在一个类中包含有虚函数,那么在创建该类对象时就会额外的增加一个数组,数组中的每一个元素都是虚函数的入口地址,不过数组和对象是分开存储的,对象中包含了数组的首地址,这个数组就是虚函数表(virtual function table),简写为vtable。
例子:
#include <stdio.h>
#include <string>
using namespace std;
class People
{
public:
virtual void display()
{
printf("People::display()\n");
}
virtual void eating()
{
printf("People::eating()\n");
}
string m_name;
int m_age;
};
class Student: public People
{
public:
virtual void display()
{
printf("Student::display()\n");
}
virtual void examing()
{
printf("Student::examing()\n");
}
float m_score;
};
class Senior: public Student
{
public:
virtual void display()
{
printf("Senior::display()\n");
}
virtual void partying()
{
printf("Senior::partying()\n");
}
bool m_hasJob;
};
int main()
{
People *p = new People();
p -> display();
p = new Student();
p -> display();
p = new Senior();
p -> display();
return 0;
}
输出:
People::display()
Student::display()
Senior::display()
各个类的对象内存模型如下所示:
int main()
{
People *pPe = new People();
People *pSt = new Student();
People *pSe = new Senior();
void (*pFunc)();
printf("-------------------People对象------------------\n");
pFunc = (void (*)())*(*(long **)pPe);
pFunc();
pFunc = (void (*)())*(++(*(long **)pPe));
pFunc();
printf("-------------------Student对象------------------\n");
pFunc = (void (*)())*(*(long **)pSt);
pFunc();
pFunc = (void (*)())*(++(*(long **)pSt));
pFunc();
pFunc = (void (*)())*(++(*(long **)pSt));
pFunc();
printf("-------------------Senior对象------------------\n");
pFunc = (void (*)())*(*(long **)pSe);
pFunc();
pFunc = (void (*)())*(++(*(long **)pSe));
pFunc();
pFunc = (void (*)())*(++(*(long **)pSe));
pFunc();
pFunc = (void (*)())*(++(*(long **)pSe));
pFunc();
return 0;
}
输出:
-------------------People对象------------------
People::display()
People::eating()
-------------------Student对象------------------
Student::display()
People::eating()
Student::examing()
-------------------Senior对象------------------
Senior::display()
People::eating()
Student::examing()
Senior::partying()
刚好和上面的对象模型符合。