純虛函數和抽象類

什麼是純虛函數

純虛函數是一種特殊的虛函數,前面分析過虛函數,虛函數是virtual修飾的類的成員函數,可以有實現。而純虛函數也和虛函數一樣,用virtual來修飾的類的成員函數,但是只能有函數體不能有具體實現

一般格式:

class <類名>
{
    virtual <類型><函數名>(<參數表>) = 0;
    ...
}

1、純虛函數是一個在父類中只有函數體,沒有實現,實現在子類中去完成

2、純虛函數爲各子類提供了一個公共界面(接口的封裝和設計、軟件的模塊功能劃分)

3、一個具有純虛函數的父類也稱爲抽象類

爲什麼要用到純虛函數(抽象類)

1、爲了方便使用多態特性

2、在很多情況下,父類本身生成對象是不合理的。例如,動物作爲一個父類可以派生出貓、狗等子類,但動物本身生成對象明顯不合理。

#pragma warning(disable : 4996)
#include <iostream>
using namespace std;

class Animal
{
public:
    Animal() 
    {
        this->m_a = 1;
        cout << "Animal: 構造函數" << endl;
    }
    ~Animal() {}
    virtual void Call()
    {
        cout << "Animal: Call" << endl;
    }
    virtual void Eat() = 0;
private:
    int m_a;
};

class Cat:public Animal
{
public:
    Cat() 
    {
        this->m_a = 2;
        cout << "Cat: 構造函數" << endl;
    }
    ~Cat() {}
    virtual void Call()
    {
        cout << "Cat: Call" << endl;
    }
    void Eat()
    {
        cout << "Cat: Eat" << endl;
    }
private:
    int m_a;
};

//不允許使用抽象類作函數參數
//void Test(Animal a){}

int main()
{
    //Animal a1;//不允許使用抽象類類型
    //Animal a2();//不允許返回抽象類
    //Test(a1);//不允許使用抽象類作函數參數

    Animal *a = new Cat();
    a->Call();
    a->Eat();

    Cat c;
    Animal &a1 = c;
    a1.Call();
    a1.Eat();

    printf("父類佔內存大小:%d, 子類佔內存大小:%d\n", sizeof(Animal), sizeof(Cat));
    system("pause");
    return 0;
}

如上面的例子,我們可以總結對抽象類做哪些操作是合理的:

1、可以聲明抽象類的指針:Animal *cat = new Cat();

2、可以聲明抽象類的引用:Animal &cat

抽象類在多繼承中的應用

C++中沒有接口這個概念,學過其他高級語言的朋友可能接觸過了接口(協議)這個概念,那麼C++中的抽象類就是模擬的這種機制。但是在繼承中高級語言不能繼承多個父類,可以繼承多個接口,C++中沒有接口這個概念,但可以繼承多個類,那就是多繼承概念。

絕大多數面嚮對象語言都不支持多繼承,絕大多數面嚮對象語言都支持接口的概念,C++中沒有接口的概念,C++中可以使用純虛函數實現接口接口類中只有函數原型定義,沒有任何數據的定義

class Interface1
{
public:
    virtual void print() = 0;
    virtual int add(int a, int b) = 0;
};

class Interface2
{
public:
    virtual void print() = 0;
    virtual int add(int a, int b) = 0;
    virtual int minus(int a, int b) = 0;
};

class parent
{
public:
    int a;
};

class Child : public parent, public Interface1, public Interface2
{
public:
    void print()
    {
        cout << "Child::print" << endl;
    }
    int add(int a, int b)
    {
        return a + b;
    }
    int minus(int a, int b)
    {
        return a - b;
    }
};

int main()
{
    Child c;
    c.print();

    cout << c.add(3, 5) << endl;
    cout << c.minus(4, 6) << endl;

    Interface1* i1 = &c;
    Interface2* i2 = &c;

    cout << i1->add(7, 8) << endl;
    cout << i2->add(7, 8) << endl;

    system("pause");
    return 0;
}

由上面的例子可以得出:

  • 多重繼承接口不會帶來二義性和複雜性等問題  
  • 多重繼承可以通過精心設計用單繼承和接口來代替
  • 接口類只是一個功能說明,而不是功能實現。
  • 子類需要根據功能說明定義功能實現。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章