JAVA與C++的多型異同

saucej發表於2015-01-07
 Java中的多型。

將一個方法呼叫同一個方法主體(大多時候為派生類)關聯起來被稱做繫結。在程式執行前進行繫結,由編譯器和連結程式實現稱為前期繫結。

後期繫結:也稱動態繫結(在程式執行過程中動態實現繫結)如果一種語言想實現後期繫結,就必須具有某種機制,以便在執行時能判斷物件的型別,從而呼叫適當的方法。 也就是說,編譯器不知道物件的型別,但是方法呼叫機制能找到正確的方法體,並加以呼叫。後期繫結機制隨程式語言的不同而有所不同。

JAVA中除了static 方法和final方法之外,其他所有的方法都是後期繫結。(也就是說,後期繫結會自動發生)

EX:

//shape/Shape.java

package polymorehism.shape

import static net.arborj.util.Print.* //簡化print的一個工程類

public class Shape{

         public void draw(){

                   print("Shape draw");

         }

}

//:shape/ Circle.java

package polymorehism.shape

public class Circle externs Shape{

         public void draw(){

                   print("Circle drwa");

         }

}

//shape/ Square.java

package polymorehism.shape

public class Square externs Shape{

         public void draw()

         {

                   print("Square draw");

         }

}

public class Main{

         public static void main(String[] args){

                   Shape s = new Circle;

                   s.draw();

         }

}

//輸出(子類成員): Circle draw

多型也不適用於屬性。

這裡雖然是一個Shape引用,後期繫結(多型)中呼叫了Circle.draw()方法。 注意Shape類中的draw方法不能是static ,(private或者final) static方法與類本身關聯,與物件無關,而private方法屬於finnal方法,派生類(也叫匯出類) 不能訪問,實現的重名draw()是一個全新的函式(與基類無關) ,故如果通過基類引用呼叫,只會呼叫基類方法(不能按照我們所期望的來執行。

還有基類中的屬性也不適用於多型。

--------------------JAVA中多型與工廠(factory)

生成工廠類Generator:

public class RandomShapeGenerator{

         private Random rand = new rand(47);

         public Shape next(){

                   switch(rand.next(3)){

                            default:

                            case 0 :return new Circle();

                            case 1 :return new Square();

                            case 2 :return new Triangle();

                   }

         }

}

public class Shapes{

         private static RandomShapeGenerator gen = new RandomShapeGenerator;

         public static void main(Strings[] args){

                   Shape[] s= new Shape[9];

                   for(int i=0;i<9;i++)

                   {

                            s[i]=gen.next();

                            for(Shape shp:s)

                            {

                                     shp.draw();

                            }

                   }

         }

}

Shape基類為自它繼承而來的所有匯出類建立了一個公共介面。 RandomShapeGenerator是一個工廠類,它在每次隨機選擇的Shape物件產生一個引用(我們可以通過對工廠類傳遞引數從而通過switch返回我們需要的子類引用)。 因為程式只與基類介面通訊,這樣的程式可擴充套件的,

可以從通用的基類繼承出新的資料型別,從而新增一些新功能。(為基類新增新函式)而那些操縱基類介面的方法不需要任何改動就可以應用於新類。(將改變的事務與未變的食物分離開的)

 

-----------------------------------------C++中的多型。

先來看跟JAVA相同例子:

class Shape{

public:

         void draw();

}

void Shape::draw(){

         pirntf("Shape draw");

}

 

class Circle:public Shape{

public:

         void draw();

}

Circle::draw(){

         printf("Circle draw");

}

class Square:public Shape{

public:

         void draw();

}

Circle::draw(){

         prinf("Square draw ");

}

int main()

{

         Circle sc1;

         Square sc2;

         Shape *s[] = {&sc1,&sc2};

         for(int i=0;i<2;i++)

         {

                   s[i]->draw();

         }

}

//輸出基類成員Shape draw  Shape draw

即通過基類指標呼叫的都是基類中定義的函式,派生類中的函式不會被呼叫

C++中的多型依賴於虛函

虛擬函式必須是非靜態的成員函式。

虛擬函式的宣告只能出現在類定義中的函式原型宣告中,而不能在成員函式實現的時候。

賦值相容規則:在需要基類物件的任何地方都可以使用公有派生類的物件。

1:派生類物件可以賦值給基類物件。

2:派生類對戲那個可以初始化基類的引用。

3:派生類物件地址可以賦值給指向基類的指標。

C++執行時多型滿足三個條件:1,類之間滿足賦值相容規則。2基類中虛擬函式用virtual宣告。

3:由成員函式來呼叫或者通過指標,引用來訪問虛擬函式。

改進:

class Shape{

public:

         virtual  void draw();

}

void Shape::draw(){

         pirntf("Shape draw");

}

 

class Circle:public Shape{

public:

          void draw(); //覆蓋基類的虛擬函式

}

Circle::draw(){

         printf("Circle");

}

class Square:public Shape{

public:

         void draw(); //覆蓋基類的虛擬函式

}

Circle::draw(){

         prinf("Square");

         //Shape::draw(); 可以通過這種方式呼叫基類被覆蓋的函式。

}

int main()

{

         Circle sc1;

         Square sc2;

         Shape *s[] = {&sc1,&sc2};

         for(int i=0;i<2;i++)

         {

                   s[i]->draw();

         }

}

//輸出子類成員:Circle draw , Square draw .

必須要通過指標或者引用來訪問虛擬函式,如果是通過物件名來訪問虛擬函式,則繫結在編譯過程中就可以進行(靜態繫結),而無需在執行過程進行。(

相關文章