虚拟函数-4、纯虚拟函数
在示例2.3中,基类CCustEdit定义了虚拟函数BuildValues()为子类提供重载的形式,而这个虚拟函数本身从来就没有执行过,也没有执行的必要。并且,由基类CCustEdit实例化的对象也没有什么应用价值。CCustEdit类白白浪费了资源。对于这种情况,可以将基类的虚拟函数定义为纯虚函数。
纯虚拟函数没有函数体,专为派生类提供重载的形式。只要形象地将虚拟函数赋值为0,即定义了纯虚函数。例如:
void virtual BuildValues(char * Statement)=0;
定义了纯虚函数的类称为抽象基类。抽象基类节省了内存空间,但不能用来实例化对象。其派生类必须重载所有的纯虚函数,否则产生编译错误。
纯虚函数和常规虚函数可以同时出现在一个类中,即抽象基类中也可以定义常规虚函数。示例2.5是对示例2.4的改写,其中基类Ca已定义为抽象基类。此基类包含一个纯虚函数OutputTitle()和一个常规虚函数OutputStyle(),以及一个虚析构函数。
示例清单2.5
#include "stdio.h"
#include "string.h"
class Ca
{
public:
Ca(){m_Style=0;}
Ca(int style){m_Style=style;}
//虚析构函数
virtual ~Ca(){ printf(“~ca() called\n”);}
//常规虚函数
virtual void OutputStyle()
{
printf("%d\n",m_Style);
}
//纯虚函数
virtual void OutputTitle()=0;
protected:
int m_Style;
};
class Cb:public Ca
{
public:
Cb(){ m_pTitle=NULL;}
Cb(const char* Title,int Style=0);
~Cb()
{
if(NULL!=m_pTitle)
delete[] m_pTitle;
printf("~cb() called\n");
}
virtual void OutputStyle()
{
printf("%d\n",~m_Style);
}
virtual void OutputTitle()
{
if(NULL!=m_pTitle)
printf("%s\n",m_pTitle);
}
private:
char *m_pTitle;
};
Cb::Cb(const char* Title,int Style):Ca(Style)
{
if(NULL==Title)
m_pTitle=NULL;
else
{ m_pTitle=new char[strlen(Title)+1];
strcpy(m_pTitle,Title);
}
}
int main(int argc, char* argv[])
{
Ca* pa=new Cb("Fairy");
//调用基类定义的常规虚函数
//由于抽象基类不能实例化对象,只能通过类名限定的方法调用它的常规虚函数
pa->Ca::OutputStyle();
//调用派生类重载的虚函数
pa->OutputStyle();
pa->OutputTitle();
//释放堆中的派生类对象,将首先调用派生类的析构函数
delete pa;
return 0;
}
程序输出结果:
0
-1
Fairy
~cb() called
~ca() called
抽象基类虽然不能实例化,但它可以定义整个类家族通用的成员变量和成员函数,为派生类提供一个框架。抽象基类为派生类提供了虚拟函数的重载形式,可以用抽象基类的指针引用派生类的对象,这为虚函数的应用准备了必要条件。