二級C++多態(tài)性:多態(tài)性和虛函數(shù)

字號:

1、 靜態(tài)聯(lián)編和動態(tài)聯(lián)編:
    • 聯(lián)編:是指一個計算機程序自身彼此關聯(lián)的過程。按聯(lián)編所進行的階段不同,可分為兩種不同的聯(lián)編方法。一種是靜態(tài)聯(lián)編,一種是動態(tài)聯(lián)編。
    • 靜態(tài)聯(lián)編:聯(lián)編工作出現(xiàn)在編譯連接階段,這種聯(lián)編過程在程序開始運行之前完成。
    例如:一個靜態(tài)聯(lián)編的例子。
    #include
    class Point
    {
    public:
    Point(double I,double j)
    { x=I;y=j;}
    double Area(){return 0.0;}
    private:
    double x,y;
    };
    class Rectangle :public Point
    {
    public:
    Rectangle(double i,double j,double k,double l);
    Double Area()
    {return w*h;}
    private:
    double w,h;
    };
    Rectangle::Rectangle(double i,double j
    ,double k,double l):point(i,j)
    {
    w=k;h=l;
    }
    void fun(point &s)
    {
    cout<
    }
    void main()
    {
    Rectangle rec(3.0,5.2,15.0,25.0);
    Fun(rec);
    }
    分析程序:在 fun() 函數(shù)中, s 所引用對象執(zhí)行的 Area() 操作被關聯(lián)到 point::Area() 的實現(xiàn)代碼上。這是靜態(tài)聯(lián)編的結果。在程序編譯階段,對 s 所引用 的對象所執(zhí)行 的 Area() 操作只能束定到 point 類的函數(shù)上。
    所以執(zhí)行結果為: 0
    • 動態(tài)聯(lián)編:有時編譯程序在編譯階段,并不能確切知道將要調用的函數(shù),只有在程序執(zhí)行時才能確定將要調用的函數(shù),為此,要確切知道調用的函數(shù),要求聯(lián)編工作要在程序運行時進行,這種在程序運行時進行聯(lián)編工作被稱為動態(tài)聯(lián)編。
    動態(tài)聯(lián)編是在虛函數(shù)的支持下實現(xiàn)的。
    所以靜態(tài)聯(lián)編和動態(tài)聯(lián)編也都屬于多態(tài)性,它們是在不同階段對不同實現(xiàn)進行的選擇。
    2、 虛函數(shù):(是成員函數(shù),且是非 static 的)
    • 格式: virtual < 類型說明符 >< 函數(shù)名 >(< 參數(shù)表 >)
    • 說明:①如果某類中的成員函數(shù)被說明 為虛函數(shù),就意味著該成員函數(shù)在派生類中可能有不同的實現(xiàn)。當使用這個成員函數(shù)操作 指針或引用 所標識對象時,對該成員函數(shù)調用采用動態(tài)聯(lián)編方式,即在運行時進行束定。
    • 態(tài)聯(lián)編只能通過指針或引用標識對象來操作虛函數(shù)。若采用一般類型的標識對象來操作虛函數(shù),則采用靜態(tài)聯(lián)編方式調用虛函數(shù)。
    例如:一個動態(tài)聯(lián)編的例子:
    #include
    class point
    {
    public:
    point(double I,double j)
    {x=I;y=j;}
    virtual double Area()
    {return 0.0;}
    private:
    double x,y;
    };
    class Rectangle:public point
    {
    public:
    Rectangle(double I,double j,double k,double l);
    Virtual double Area()
    {
    return w*h;
    }
    private:
    ouble w,h;
    };
    Rectangle::Rectangle(double I,double j,
    double k,double l):point(I,j)
    {
    w=k;h=l;
    }
    void fun(point &s) // 被動態(tài)聯(lián)編
    {
    cout<
    }
    void main()
    {
    Rectangle rec(3.0,5.2,15.0,25.0);
    Fun(rec);
    }
    輸出結果: 375
    • 派生類中對基類的虛函數(shù)進行替換時,要求派生類中說明的虛函數(shù)與基類中被替換的虛函數(shù)之間滿足如下條件:
    • 與基類的虛函數(shù)有相同的參數(shù)個數(shù)。
    • 其參數(shù)的類型與基類的虛函數(shù)的對應參數(shù)類型相同。
    • 其返回值或者與基類虛函數(shù)相同,或者都返回指針或引用。
    滿足上述條件的派生類的成員函數(shù),自然是虛函數(shù),可以不加 virtual.
    例如:分析下列程序輸出結果,并回答問題:
    #include
    class A
    {
    public:
    virtual void act1();
    void act2()
    {
    act1();
    }
    };
    void A::act1()
    { cout<<”A::act1() called.”<
    class B:public A
    {
    public:
    void act1();
    }
    void B::act1()
    {cout<<”B::act1() called.”<
    void main()
    {
    B b;
    b.act2();
    }
    回答問題:①該程序執(zhí)行后的輸出結果是什么?為什么?
    答: B::act1() called.
    因為 B 是 A 的派生類, act1() 是 A 類的虛函數(shù) , 類 B 中的 act1() 自然是虛函數(shù)。在 main() 函數(shù)中, b.act2(), 調用類 B 中的 act2() 函數(shù), B 是派生類,實際上調用 A::act2(), 而 A::act2() 函數(shù)的實現(xiàn)中調用 act1(), 由于有兩個 act1() 函數(shù),并且是虛函數(shù),產生了動態(tài)聯(lián)編,根據(jù)運行情況,選擇了 B::act1();
    • 如果將 A::act2() 的實現(xiàn)改為:
    void A::act2()
    {
    this → act1();
    }
    輸出結果如何?
    答: B::act1() called.
    因為 this 是指向操作該成員函數(shù)的對象的指針。
    • 如果將 A::act2() 的實現(xiàn)改為:
    void A::act2()
    {
    a::act1();
    }
    輸出結果如何?
    答: A::act1() called.
    • 虛函數(shù)的限制:
    一個類中將所有的成員函數(shù)都盡可能 地設置為虛函數(shù)總是有益的。它除了會增加一些系統(tǒng)開銷,沒有其他壞處。但是設置虛函數(shù)應注意:
    • 只有類的成員函數(shù)才能 說明為虛函數(shù)。這是因為虛函數(shù)僅使用于有繼承 關系的類對象,所以普通函數(shù)不能說明為虛函數(shù)。