程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++學習之多態

C++學習之多態

編輯:C++入門知識

C++的類機制中有支持多態的技術來解決抽象編程,它用的是一種滯後捆綁技術,
這種技術,通過預先設定其成員函數的虛函數性質,使得任何捆綁該成員函數的未定類型的對象操作在編譯時,都以一個不確定的指針特殊地“引命代發”來編碼,
到了運行時,遇到確定類型的對象,才突然制定其真正的行為。即滯後到運行時,根據具體類型的對象來捆綁成員函數,這樣,辨別對象類型的工作就可以不用用戶做了。

虛函數(Virtual Function)
1.多態條件(Polymorphism Condition)
使用類編程中,要能進行抽象編程,不隨類的改動而改動,類機制必須解決這個問題,在C++中,就是虛函數機制。基類與派生類的同名操作。只要標記上virtual,則該操作便具有多態性。
如下代碼所示:

[cpp] 
#include <iostream> 
using namespace std; 
 
class Base 

public: 
    virtual void fun() 
    { 
        cout << "In Base class" << endl; 
    } 
}; 
 
class Sub : public Base 

public: 
    virtual void fun() 
    { 
        cout << "In Sub class" << endl; 
    } 
}; 
 
void test(Base& b) 

    b.fun(); 

 
int main() 

    Base bc; 
    Sub sc; 
    test(bc); 
    test(sc); 
 
    return 0; 

代碼輸出如下:

[plain] 
In Base class 
In Sub class 

 

上述代碼中fun是Base類的虛函數,一旦標記了基類的函數為虛函數,則後面繼承類中一切同名成員函數都編程了虛函數,在test函數中,b是Base類的引用性形參,Base類對象和Sub類對象都可以作為實參傳給形參b。

 

如果函數參數是實際復制動作的傳遞,則子類對象完全變成基類對象了,這樣,便不會有多態了。如將上述代碼中的test函數參數改為如下形式時,

如下代碼所示:

[cpp] 
void test(Base b) 

    b.fun(); 

 
int main() 

    Base bc; 
    Sub sc; 
    test(bc); 
    test(sc); 
 
    return 0; 

其輸出則變為:

[plain] 
In Base class 
In Base class 

因為對於這種參數的傳遞過程已經將對象的性質做了肯定的轉變,而對於確定的對象,是沒有選擇操作可言的。因此,對於多態,僅僅對於對象的指針和引用的間接訪問,才會發生多態現象。

 

2. 虛函數機理

在上述代碼中,b.fun()函數調用顯示出多樣性,其編譯不能立即確定fun的確切位置,即不能確定到底是調用基類Base的fun函數,還是子類Sub的fun函數。

當編譯器看到fun的虛函數標志時,以放入虛函數表中,等到遇到b.fun()這個虛函數的調用時,便將該捆綁操作滯後到運行中,以實際的對象類型來實際捆綁其對應的成員函數操作。當然編譯器不可能跟蹤到運行的程序中去,而是在捆綁操作b.fun()處避開函數調用,只做一個指向實際對象的成員函數的間接訪問。如此,實際對象若是基類,則調用的就是基類成員函數,若是子類,則調用的就是子類的成員函數。當然,每一個實際的對象都必須額外占有一個指針空間,以指向類中的虛函數表。如下圖所示。

 

從圖中可以看處,用了虛函數的類,其對象的空間比不用虛函數的類多了一個指針的空間,由於涉及了其他的操作,包括間接訪問虛函數,對象的指針偏移量計算等,所以在應用了虛函數後,會影響程序的運行效率。

 

3.虛函數的傳播

虛函數在繼承層次結構中總是會自動地從基類傳播下去。因此,上述代碼中Sub類中的成員函數fun的virtual說明可以省略,

例如下面的例子:

在一個平面形狀類的體系中,基類shape有兩個子類:圓Circle類和長方形Retangle類,專門負責求面積的Area函數在基類中設置為virtual就能使子類的響應同名函數虛擬化。

[plain] 
#include<iostream> 
#include <cmath> 
 
using namespace std; 
 
class Shape 

protected: 
    double xCoord, yCoord; 
public: 
    Shape(double x, double y) 
    { 
        xCoord = x; 
        yCoord = y; 
    } 
    virtual double area()const 
    { 
        return 0.0; 
    } 
}; 
 
class Circle : public Shape 

protected: 
    double radius; 
public: 
    Circle(double x, double y, double r) : Shape(x, y) 
    { 
        radius = r; 
    } 
    double area()const 
    { 
        return 3.14 * radius * radius; 
    } 
}; 
 
class Rectangle : public Shape 

protected: 
    double x2Coord, y2Coord; 
public: 
    Rectangle(double x1, double y1, double x2, double y2) : Shape(x1, y1) 
    { 
        x2Coord = x2; 
        y2Coord = y2; 
    } 
    double area()const; 
}; 
 
double Rectangle::area()const 

    return abs((xCoord - x2Coord) * (yCoord - y2Coord)); 

 
void fun(const Shape& sp) 

    cout << sp.area() << endl; 

 
int main() 

    fun(Circle(2, 5, 4)); 
    fun(Rectangle(2, 4, 1, 2)); 
 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved