1. 程式人生 > >4.6 C++抽象基類和純虛成員函數

4.6 C++抽象基類和純虛成員函數

中新 error isp ... 先來 必須 pub 對象 c++

參考:http://www.weixueyuan.net/view/6376.html

總結:

  在C++中,可以通過抽象基類來實現公共接口

  純虛成員函數沒有函數體,只有函數聲明,在純虛函數聲明結尾加上“=0”表明此函數為純虛成員函數。

  包含純虛成員函數的類即為抽象基類,之所以說它抽象,那是因為它無法實例化,也即無法用於創建對象。

  純虛成員函數可以被派生類繼承,如果派生類不重新定義抽象基類中的所有(有多個則要重新定義多個)純虛成員函數,則派生類同樣會成為抽象基類,因而也不能用於創建對象。

  一個純虛成員函數就可以使類成為抽象基類,但是抽象基類中除了包含純虛成員函數外,同樣可以包含其它成員函數或成員變量。

  只有類中的虛函數才能被聲明為純虛成員函數,普通成員函數和頂層函數均不能聲明為純虛成員函數。

  抽象基類可以用於實現公共接口,在抽象基類中聲明的純虛成員函數,派生類如果想要能夠創建對象,則必須全部重新定義這些純虛成員函數。  

--------------------------

公共接口是指一系列成員函數的集合,支持該接口的類必須以合適的方式重新定義這些成員函數,否則就無法創建對象。在C++中,可以通過抽象基類來實現公共接口。為了介紹抽象基類,我們需要先來了解一下純虛成員函數。

純虛成員函數的聲明語法如下:
virtual 函數返回類型 函數名 (函數參數) = 0;

純虛成員函數沒有函數體,只有函數聲明,在純虛函數聲明結尾加上“=0”表明此函數為純虛成員函數。



包含純虛成員函數的類即為抽象基類,之所以說它抽象,那是因為它無法實例化,也即無法用於創建對象。

例1:

#include<iostream>
using namespace std;

class base
{
public :
    virtual void display() = 0;
    //......
};

int main()
{
    base b; //compile error
    return 0;
}

如本例所示,本例中只定義了一個base類,該類中聲明了一個純虛成員函數,包含純虛成員函數的類即為抽象基類,因此base類為抽象基類。抽象基類是無法用於創建對象的,而主函數中我們嘗試創建base類的對象,這是不允許的,編譯提示語法錯誤。

純虛成員函數可以被派生類繼承,如果派生類不重新定義抽象基類中的所有(有多個則要重新定義多個)純虛成員函數,則派生類同樣會成為抽象基類,因而也不能用於創建對象。



例2:

#include<iostream>
using namespace std;

class base
{
public :
    base(){x = 0;}
    base(int a){x = a;}
    virtual void display() = 0;
    int getx(){return x;}
private:
    int x;
};

class derived1 : public base
{
public:
    derived1(int a){ y = a;}
private:
    int y;
};

class derived2 : public base
{
public:
    derived2(int a, int b):base(a){ z = b;}
    void display()
    {
        cout<<getx()<<" "<<z<<endl;
    }
private:
    int z;
}

int main()
{
    base b;    //compile error
    derived1 d1(5);   //compile error
    derived2 d2(5,6);
    d2.display();
    return 0;
}

在本例中定義了三個類,一個base類,base類中有一個整型成員變量x,成員函數有兩個構造函數、一個getx普通成員函數和一個純虛成員函數display。之後定義了一個derived1類,該類繼承base類,在該類中新增一個整型的成員變量y,並且定義了一個構造函數。之後又定義了一個derived2類,這個類同樣也新增了一個整型的成員變量z,定義了一個帶參的構造函數,並顯式調用了基類中的構造函數,除此之外derived2類還重新定義了基類中的純虛成員函數display,派生類中的display函數與基類中的純虛成員函數構成函數覆蓋。我們再來看一下主函數中的情況,主函數中首先嘗試創建base類的對象,因為base類包含一個純虛成員函數,因此是抽象基類,不能創建對象。之後又嘗試創建derived1的對象,derived1類繼承了基類base中的純虛成員函數,並且沒有重新定義該函數,因此derived1類雖然是base類的派生類,但它仍然是抽象基類,因此同樣不能創建對象。之後嘗試創建derived2類的對象,該類同樣是base類的派生類,同樣從base類中繼承了純虛成員函數display,但是該類中同時也重新定義了該函數,因此覆蓋了基類的純虛成員函數,該類不是抽象基類,因此可以創建對象。創建derived2類的對象時調用了類中的帶參構造函數,之後通過對象調用display函數,打印出成員變量x和y的值。

一個純虛成員函數就可以使類成為抽象基類,但是抽象基類中除了包含純虛成員函數外,同樣可以包含其它成員函數或成員變量。如例2中所示的base類,類中除了包含純虛成員函數之外,還包含了一個private成員變量x和兩個構造函數及一個普通成員函數getx。

只有類中的虛函數才能被聲明為純虛成員函數,普通成員函數和頂層函數均不能聲明為純虛成員函數。如例3中企圖將頂層函數和普通的成員函數聲明為純虛成員函數,這都是不允許的。

例3:

void fun() = 0;   //compile error

class base
{
public :
    void display() = 0;  //compile error
    //......
};

抽象基類可以用於實現公共接口,在抽象基類中聲明的純虛成員函數,派生類如果想要能夠創建對象,則必須全部重新定義這些純虛成員函數。

4.6 C++抽象基類和純虛成員函數