纯虚函数和抽象类

纯虚函数

纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但要求在它的派生类中必须定义自己的版本, 或重新说明为纯虚函数。

纯虚函数的定义形式

virtual <函数类型> <函数名> ( 参数表 ) = 0

纯虚函数与一般虚函数成员的原型在书写形式上的不同就在于后面加了“=0”,表明在基类中不用定义该函数,它的实现部分(函数体) 留给派生类去做。

  • 纯虚函数没有函数体;
  • 最后面的“=0”并不表示函数返回值为0;
  • 这是一个声明语句,最后应有分号。
  • 纯虚函数只有函数的名字而不具备函数的功能,不能被调用。在派生类中对此函数提供定义后,它才能具备函数的功能,可被调用。
  • 如果在一个类中声明了纯虚函数,而在其派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。
  • 一个具有纯虚函数的类称为抽象类。
例:纯虚函数的使用
#include<iostream.h>
class Circle {
public:
    void setr(int x){ r=x; }
    virtual void show()=0; // 纯虚函数
protected:
    int r;
};
class Area:public Circle{
public:
    void show(){ cout<<"Area is "<<3.14*r*r<<endl;}
}; // 重定义虚函数show( )
class Perimeter:public Circle{
public:
    void show(){cout<<"Perimeter is "<<2*3.14*r<<endl;}
}; // 重定义虚函数show( )
void main(){
    Circle *ptr;
    Area ob1;
    Perimeter ob2;
    ob1.setr(10);
    ob2.setr(10);
    ptr=&ob1;
    ptr->show();
    ptr=&ob2;
    ptr->show();
}
Area is 314
Perimeter is 62.8

抽象类

如果一个类至少有一个纯虚函数,那么就称该类为抽象类

使用抽象类的几点规定

  • (1)由于抽象类中至少包含一个没有定义功能的纯虚函数。因此,抽象类只能作为其他类的基类来使用, 不能建立抽象类对象,纯虚函数的实现由派生类给出。
  • (2)不允许从具体类派生出抽象类。
  • (3)抽象类不能用作参数类型、函数返回类型或显式转换的类型
  • (4)可以声明指向抽象类的指针引用,此指针可以指向它的派生类,进而实现多态性。
  • (5)抽象类的析构函数可以被声明为纯虚函数,这时,应该至少提供该析构函数的一个实现
  • (6)如果派生类中没有重定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不是抽象类了,它是一个可以建立对象的具体类。
  • (7)在抽象类中也可以定义普通成员函数或虚函数,虽然不能为抽象类声明对象,但仍然可以通过派生类对象来调用这些不是纯虚函数的函数。
class Shape {
public:
    virtual void rotateshape(int)=0;
    virtual void drawshape()=0;
    virtual void hiliteshape()=0;
    //...
};
Shape s1; //错误,不能建立抽象类的对象
Shape* ptr; //正确,可以声明指向抽象类的指针
Shape f(); //错误,抽象类不能作为函数的返回类型
Shape g(shape s); //错误,抽象类不能作为函数的参数类型
Shape& h(shape&); //正确,可以声明抽象类的引用•
例:演示抽象类和纯虚函数
#include <iostream.h>
const double PI = 3.14159 ;
class Shapes { //抽象基类Shapes声明
protected:
    int x, y ;
public:
    void setvalue( int xx, int yy=0 ) { x=xx ; y=yy ; }
    virtual void display( ) = 0 ; //纯虚函数成员
};
class Rectangle:public Shapes { //派生类Rectangle声明
public:
    void display( ) //虚成员函数
    { cout<<"The area of rectangle is : "<<x*y<<endl ; }
};
class Circle:public Shapes { //派生类Circle声明
public:
    void display( ) //虚成员函数
    { cout<<"The area of circle is : "<<PI*x*x<<endl ; }
};
void main(){
    Shapes *ptr[2] ; //声明抽象基类指针
    Rectangle rect ; //声明派生类对象rect
    Circle cir ; //声明派生类对象cir
    ptr[0] = &rect ; //抽象基类指针指向Rectangle对象
    ptr[0]->setvalue(5, 8) ; //设置矩形边长
    ptr[0]->display( ) ; //调用rect虚成员函数显示矩形面积
    ptr[1] = &cir ; //抽象基类指针指向Circle类对象
    ptr[1]->setvalue(10) ; //设置圆形半径
    ptr[1]->display( ) ; //调用cir虚成员函数显示圆形面积
}

程序运行结果为:

The area of rectangle is: 40
The area of circle is : 314.159

程序中类Shapes、Rectangle和Circle属于同一个类族,抽象类Shapes通过纯虚函数为整个类族提供了通用的外部接口。通过公有派生而来的子类,给出了纯虚函数的具体函数体实现,因此是非抽象类。我们可以定义非抽象类的对象,同时根据赋值兼容规则,抽象类Shapes类型的指针也可以指向任何一个派生类的对象,通过基类Shapes的指针可以访问到正在指向的派生类Rectangle和Circle类对象的成员,这样就实现了对同一类族中的对象进行统一的多态处理。