虚函数:
一旦基类Person中有虚函数virtual func,其子类Chiid中如果有重写override该函数func的,无论其是否申明为virtual,派生类对其重定义申明的函数均为virtual。
对于含有虚函数的类来说:
1、虚函数表是与类关联的,也就是说,一个类只有一张虚函数表。(从这个方面上说,虚函数类似于类的静态函数)
2、VTable中虚函数的位置是由基类决定的,所以,哪怕你在派生类中不是按基类的顺序来重写虚函数,派生类的VTable中虚函数的存放顺序和基类的也是一样的。
3、虚函数指针vfPtr是与对象关联的,每个对象都有一个隐藏的虚函数指针,该指针指向该类的虚函数表。但是,同类对象的虚函数指针的值是相同的。因为都指向该类的虚函数表。
4、虚函数指针vfPtr的值是在调用构造函数时进行初始化的。如果该类没有构造函数,那么,默认构造函数干的唯一一件事就是初始化VPtr。所以,当你在写一个类的构造函数时,一定不要写一个空的默认构造函数。
纯虚函数:
只有声明没有实现,格式如virtual func()=0;含有纯虚函数的类叫抽象类,不能够实例化,派生类必须实现基类的纯虚函数。
虚函数的几点限制:
1. 只有类的成员函数可为虚函数;
2. 静态成员函数不能为虚函数;
3. 构造函数不能为虚函数;
4. 析构函数可以为虚函数。
对于第3点的解释,因为创建派生类对象时,基类的构造函数先于派生类的构造函数执行,所以构造函数不能为虚函数。
-----------------------------------------------------
析构函数一般申明为虚函数的原因?
见下文具体实例:
#include<stdio.h> #include<stdlib.h> class Base { public : Base() { printf("Base::Base()/n"); } virtual ~Base() { printf("Base::~Base()/n"); } }; class Derive : public Base { public : Derive() { printf("Derive::Derive()/n"); } ~Derive() { printf("Derive::~Derive()/n"); } }; void f() { Base *b = new Derive(); delete b; } int main() { f(); system("pause"); return 0; }
输出结果为:
Base::Base()
Derive::Derive()
Derive::~Derive()
Base::~Base()
如果将Base的析构函数的声明virtual去掉,结果为:
Base::Base()
Derive::Derive()
Base::~Base()
如果在Derive类的构造函数中占用了系统资源(如分配了内存),那么你在释放b的时候,如果单纯的只是调用b的析构函数,那么就会造成资源泄漏。
但是如果把析构函数声明为virutal,那么就可以先调用子类的析构函数释放资源,再调用父类的析构函数。