前面曾经提到过“种子类”,其主要用处在于代码共享,一般是通过其派生类再去实例化形成具体的对象。
现在再看一个更基础的类(主要用于多态环境)——抽象类。在具体论述抽象类之前,先看一下两个特殊的虚函数:
1,空虚函数
空虚函数是函数体为空的虚成员函数,一般形式为:
virtual void v_fun( <parameters-list> ) {} 或 virtual <return-type> v_fun( <parameters-list> ) { return <default-result> }
一个类中若含有空虚函数,则一般必须由派生类来定义一个具体的非空虚函数去置换相应的空虚函数,最后才能实例化成一个有意义的对象。由此可见空虚函数只是为派生类的多态性奠定一个基础框架,具体的多态性实现必须由各相应的派生类来加以落实。仔细分析可以看到,利用空虚函数实现上述多态性框架有一些不妥之处,其中之一就是多余代码。空虚函数本身没有意义,但却要占用代码空间。另外若用含空虚函数的类去实例化一个对象的话,此对象一般也没啥意义。下面给出含有空虚函数的状态机包装类:
// 有关"状态机"的封装
enum status_type { S0, S1, S2, S3, S4,…,Sn }; class class_SM { protected: status_type status; virtual int Fy( int x ); virtual void Fs( int x ); public: class_SM( void ) { status = S0; } class_SM( status_type S ) { status = S; } int Do_it( int x ); ~class_SM() {} };
int class_SM :: Fy( int x ) { // return Fy( x, status )
return x; }
void class_SM :: Fs( int x ) { // status <- Fs( x, status ) }
int class_SM :: Do_it( int x ) { int result; result = Fy( x ); Fs( x ); return result; }
其中Fy和Fs都是空虚函数。
2,纯虚函数
纯虚函数是一种纯粹虚设的函数,一般形式为:
virtual void v_fun( <parameters-list> ) = 0; 或 virtual <return-type> v_fun( <parameters-list> ) = 0;
可以看出,纯虚函数没有函数体,那具体是何物呢?其实纯虚函数只是在VTAB中预留了一个值为0的单元,此单元将被其相关衍生类置换成具体的虚函数入口地址。由于纯虚函数没有函数体,所以并不占有代码空间,而只是在VTAB中预留了一个单元而已。但正是因为没有函数体,而且VTAB中的预留值是0,所以纯虚函数是不可调用的。为了限制对纯虚函数的调用,编译系统一般是不允许对含有纯虚函数的类进行实例化的。
为了区别于一般的类,含有纯虚成员函数的类被称为抽象类。由上可见,抽象类不能被实例化成对象。这样也就在语法层面上限制了无意义对象的出现。下面给出状态机的包装抽象类:
// 有关"状态机"的封装(抽象类)
enum status_type { S0, S1, S2, S3, S4,…,Sn }; class class_SM { protected: status_type status; virtual int Fy( int x ) = 0; // return Fy( x, status ) virtual void Fs( int x ) = 0; // status <- Fs( x, status ) public: class_SM( void ) { status = S0; } class_SM( status_type S ) { status = S; } int Do_it( int x ); ~class_SM() {} };
int class_SM :: Do_it( int x ) { int result; result = Fy( x ); Fs( x ); return result; } |