浙江福彩3d走势图
我們來自五湖四海,不為別的,只因有共同的愛好,為中國互聯網發展出一分力!

C++中的虛函數

2013年04月28日03:40 閱讀: 15596 次

    一.簡介

    虛函數是C++中用于實現多態(polymorphism)的機制。核心理念就是通過基類訪問派生類定義的函數。假設我們有下面的類層次:

    class A

    {

    public:

    virtual void foo() { cout << "A::foo() is called" << endl;}

    };

    class B: public A

    {

    public:

    virtual void foo() { cout << "B::foo() is called" << endl;}

    };

    那么,在使用的時候,我們可以:

    A * a = new B();

    a->foo(); // 在這里,a雖然是指向A的指針,但是被調用的函數(foo)卻是B的!

    這個例子是虛函數的一個典型應用,通過這個例子,也許你就對虛函數有了一些概念。它虛就虛在所謂“推遲聯編”或者“動態聯編”上,一個類函數的調用并不是在編譯時刻被確定的,而是在運行時刻被確定的。由于編寫代碼的時候并不能確定被調用的是基類的函數還是哪個派生類的函數,所以被成為“虛”函數。

    虛函數只能借助于指針或者引用來達到多態的效果,如果是下面這樣的代碼,則雖然是虛函數,但它不是多態的:

    class A

    {

    public:

    virtual void foo();

    };

    class B: public A

    {

    virtual void foo();

    };

    void bar()

    {

    A a;

    a.foo(); // A::foo()被調用

    }

    1.1 多態

    在了解了虛函數的意思之后,再考慮什么是多態就很容易了。仍然針對上面的類層次,但是使用的方法變的復雜了一些:

    void bar(A * a)

    {

    a->foo(); // 被調用的是A::foo() 還是B::foo()?

    }

    因為foo()是個虛函數,所以在bar這個函數中,只根據這段代碼,無從確定這里被調用的是A::foo()還是B::foo(),但是可以肯定的說:如果a指向的是A類的實例,則A::foo()被調用,如果a指向的是B類的實例,則B::foo()被調用。

    這種同一代碼可以產生不同效果的特點,被稱為“多態”。

    1.2 多態有什么用?

    多態這么神奇,但是能用來做什么呢?這個命題我難以用一兩句話概括,一般的C++教程(或者其它面向對象語言的教程)都用一個畫圖的例子來展示多態的用途,我就不再重復這個例子了,如果你不知道這個例子,隨便找本書應該都有介紹。我試圖從一個抽象的角度描述一下,回頭再結合那個畫圖的例子,也許你就更容易理解。

    在面向對象的編程中,首先會針對數據進行抽象(確定基類)和繼承(確定派生類),構成類層次。這個類層次的使用者在使用它們的時候,如果仍然在需要基類的時候寫針對基類的代碼,在需要派生類的時候寫針對派生類的代碼,就等于類層次完全暴露在使用者面前。如果這個類層次有任何的改變(增加了新類),都需要使用者“知道”(針對新類寫代碼)。這樣就增加了類層次與其使用者之間的耦合,有人把這種情況列為程序中的“bad smell”之一。

    多態可以使程序員脫離這種窘境。再回頭看看1.1中的例子,bar()作為A-B這個類層次的使用者,它并不知道這個類層次中有多少個類,每個類都叫什么,但是一樣可以很好的工作,當有一個C類從A類派生出來后,bar()也不需要“知道”(修改)。這完全歸功于多態--編譯器針對虛函數產生了可以在運行時刻確定被調用函數的代碼。

    1.3 如何“動態聯編”

 

[1] [2] 下一頁

分享到: 更多
藍客門戶
©2001-2019 中國藍客聯盟 版權所有.
關于藍客聯盟歷史宗旨章程技術服務聯系我們藍客社區

浙江福彩3d走势图