1. 程式人生 > >C++ 在繼承中虛擬函式、純虛擬函式、普通函式,三者的區別

C++ 在繼承中虛擬函式、純虛擬函式、普通函式,三者的區別

1.虛擬函式(impure virtual)

  C++的虛擬函式主要作用是“執行時多型”,父類中提供虛擬函式的實現,為子類提供預設的函式實現

  子類可以重寫父類的虛擬函式實現子類的特殊化。

  如下就是一個父類中的虛擬函式:

複製程式碼
class A
{
public:
    virtual void out2(string s)
    {
        cout<<"A(out2):"<<s<<endl;
    }
};
複製程式碼

2.純虛擬函式(pure virtual)

  C++中包含純虛擬函式的類,被稱為是“抽象類”。抽象類不能使用new出物件,只有實現了這個純虛擬函式的子類才能new出物件。

  C++中的純虛擬函式更像是“只提供申明,沒有實現”,是對子類的約束,是“介面繼承”。

  C++中的純虛擬函式也是一種“執行時多型”。

  如下面的類包含純虛擬函式,就是“抽象類”:

複製程式碼
class A
{
public:
    virtual void out1(string s)=0;
    virtual void out2(string s)
    {
        cout<<"A(out2):"<<s<<endl;
    }
};
複製程式碼

3.普通函式(no-virtual)

普通函式是靜態編譯的,沒有執行時多型,只會根據指標或引用的“字面值”類物件,呼叫自己的普通函式

  普通函式是父類為子類提供的“強制實現”。

  因此,在繼承關係中,子類不應該重寫父類的普通函式,因為函式的呼叫至於類物件的字面值有關。

4.程式綜合例項

複製程式碼
#include <iostream>
using namespace std;

class A
{
public:
    virtual void out1()=0;  ///由子類實現
    virtual ~A(){};
    virtual void out2() ///預設實現
    {
        cout<<"A(out2)"<<endl;
    }
    void out3() ///
強制實現 { cout<<"A(out3)"<<endl; } }; class B:public A { public: virtual ~B(){}; void out1() { cout<<"B(out1)"<<endl; } void out2() { cout<<"B(out2)"<<endl; } void out3() { cout<<"B(out3)"<<endl; } }; int main() { A *ab=new B; ab->out1(); ab->out2(); ab->out3(); cout<<"************************"<<endl; B *bb=new B; bb->out1(); bb->out2(); bb->out3(); delete ab; delete bb; return 0; }
複製程式碼

執行結果:

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

虛擬函式為了過載和多型的需要,在基類中是有定義的,即便定義是空,所以子類中可以重寫也可以不寫基類中的此函式!
純虛擬函式在基類中是沒有定義的,必須在子類中加以實現,很像java中的介面函式!

虛擬函式
引入原因:為了方便使用多型特性,我們常常需要在基類中定義虛擬函式。
class Cman
{
public:
virtual void Eat(){……};
void Move();
private:
};
class CChild : public CMan
{
public:
virtual void Eat(){……};
private:
};
CMan m_man;
CChild m_child;
CMan *p ;//這才是使用的精髓,如果不定義基類的指標去使用,沒有太大的意義
p = &m_man ;
p->Eat(); //始終呼叫CMan的Eat成員函式,不會呼叫 CChild 的
p = &m_child;
p->Eat();//如果子類實現(覆蓋)了該方法,則始終呼叫CChild的Eat函式
//不會呼叫CMan 的 Eat 方法;如果子類沒有實現該函式,則呼叫CMan的Eat函式

p->Move(); //子類中沒有該成員函式,所以呼叫的是基類中的


純虛擬函式
引入原因:
1、同“虛擬函式”;
2、在很多情況下,基類本身生成物件是不合情理的。例如,動物作為一個基類可以派生出老虎、孔雀等子類,但動物本身生成物件明顯不合常理。
純虛擬函式就是基類只定義了函式體,沒有實現過程,定義方法如: virtual void Eat() = 0; 不要 
在cpp中定義;純虛擬函式相當於介面,不能直接例項化,需要派生類來實現函式定義;
有的人可能在想,定義這些有什麼用啊 
,我覺得很有用,比如你想描述一些事物的屬性給別人,而自己不想去實現,就可以定義為純虛擬函式。說的再透徹一些。比如蓋樓房,你是老闆,你給建築公司描述清楚你的樓房的特性,多少層,樓頂要有個花園什麼的,建築公司就可以按照你的方法去實現了,如果你不說清楚這些,可能建築公司不太瞭解你需要樓房的特性。用純需函式就可以很好的分工合作了
虛擬函式和純虛擬函式區別
觀點一:
類裡宣告為虛擬函式的話,這個函式是實現的,哪怕是空實現,它的作用就是為了能讓這個函式在它的子類裡面可以被過載,這樣的話,這樣編譯器就可以使用後期繫結來達到多型了
純虛擬函式只是一個介面,是個函式的宣告而已,它要留到子類裡去實現。
class A{
protected:
void foo();//普通類函式
virtual void foo1();//虛擬函式
virtual void foo2() = 0;//純虛擬函式
}
觀點二:
虛擬函式在子類裡面也可以不過載的;但純虛必須在子類去實現,這就像Java的介面一樣。通常我們把很多函式加上virtual,是一個好的習慣,雖然犧牲了一些效能,但是增加了面向物件的多型性,因為你很難預料到父類裡面的這個函式不在子類裡面不去修改它的實現
觀點三:
虛擬函式的類用於“實作繼承”,繼承介面的同時也繼承了父類的實現。當然我們也可以完成自己的實現。純虛擬函式的類用於“介面繼承”,主要用於通訊協議方面。關注的是介面的統一性,實現由子類完成。一般來說,介面類中只有純虛擬函式的。
觀點四:
帶純虛擬函式的類叫虛基類,這種基類不能直接生成物件,而只有被繼承,並重寫其虛擬函式後,才能使用。這樣的類也叫抽象類。
虛擬函式是為了繼承介面和預設行為
純虛擬函式只是繼承介面,行為必須重新定義