人人做人人澡人人爽欧美,国产主播一区二区,久久久精品五月天,羞羞视频在线观看免费

當前位置:蘿卜系統下載站 > 技術開發教程 > 詳細頁面

JAVA 的interface觀念 與C++ 多重繼承的比較

JAVA 的interface觀念 與C++ 多重繼承的比較

更新時間:2022-08-29 文章作者:未知 信息來源:網絡 閱讀次數:

interface與多重繼承的觀念
不管是Java的interface或是C++的多重繼承﹐在物件導向的理論里﹐都算是蠻新穎的概念。所以這里我們談的﹐是以程式語言的角度﹐看看Java interface的所有意義與功能﹐是否C++的多重繼承能全部詮釋?或是相反地以Java的來詮釋C++的。

首先讓我們來復習一下什么是C++的多重繼承。 「繼承」通常在物件導向程式語言中﹐扮演著程式碼的重復利用的重責大任﹐而C++的多重繼承則讓某一個子類別可以繼承許多分屬于不同資料型別的父類別如下:

#include <stdio.h>

class Test1 {

public:

virtual void f1() {puts("Test1::f1()"; }

virtual void g1() {puts("Test1::g1()"; }

};

class Test2 {

public:

virtual void f2() { puts("Test2::f2()"; }

virtual void g2() { puts("Test2::g2()"; }

};

class Test3 : public Test1, public Test2 {

public:

virtual void gg() { puts("Test3::gg()"; }

};

void main() {

Test3 t3; t3.f1(); t3.f2();

t3.g1(); t3.g2(); t3.gg();

}

// 程式輸出:

Test1::f1() Test2::f2() Test1::g1()

Test2::g2() Test3::gg()

程式1﹑C++的多重繼承



根據[Rie96]﹐認為正確使用物件導向技術中之「多重繼承」觀念﹐應該如下面的例子:

假設有一個木造門﹐則:

1. 此木造門是門的一種(a kind of)。

2. 但門不是木造門的一部份(a part of)。

3. 木造門是木制品的一種。

4. 但木制品不是木造門的一部份。

5. 木制品不是門的一種。

6. 門也不是木制品的一種。



所以您可以發現﹐多重繼承在使用時﹐必須非常小心﹐而且在許多時候﹐其實我們并不需要多重繼承的。

Java也提供繼承機制﹐但還另外提供一個叫interface的概念。由于Java的繼承機制只能提供單一繼承(就是只能繼承一種父類別)﹐所以就以Java的interface來代替C++的多重繼承。interface就是一種介面﹐規定欲溝通的兩物件﹐其通訊該有的規范有哪些。如以Java程式語言的角度來看﹐Java的interface則表示:一些函數或資料成員﹐為另一些屬于不同類別的物件所需共同擁有﹐則將這些函數與資料成員﹐定義在一個interface中﹐然后讓所有不同類別的Java物件可以共同操作使用之。

所以﹐對于Java的繼承與interface﹐我們總結如下:

1.Java的class只能繼承一個父類別(用extends關鍵字)﹐但可以擁有(或稱實作)許多interface(用implements關鍵字)。

2.Java的interface可以繼承許多別的interface(也是用extends關鍵字)﹐但不可以實作任何interface。



因此﹐我們可以利用Java的interface來模擬C++的多重繼承。如上面的例子可以轉化如下:

interface Test1 {

public void f1();

public void g1();

}

interface Test2 {

public void f2();

public void g2();

}

interface Test3 extends Test1, Test2 {

public void gg();

}

class CTest implements Test3 {

public void f1() { System.out.println("Test1::f1()"; }

public void g1() { System.out.println("Test1::g1()"; }

public void f2() { System.out.println("Test2::f2()"; }

public void g2() { System.out.println("Test2::g2()"; }

public void gg() { System.out.println("Test3::gg()"; }

}

class Run {

public void run() {

CTest ct=new CTest(); ct.f1();ct.f2();

ct.g1();ct.g2(); ct.gg();

}}

class Main {

public static void main (String args[]) {

Run rr=new Run();

rr.run();

}}

// 程式輸出:

Test1::f1() Test2::f2() Test1::g1()

Test2::g2() Test3::gg()

程式2﹑利用Java的interface完成C++的多重繼承功能



然而﹐根據[Ait96]的文章顯示﹐他認為Java的interface比C++的多重繼承好學很多﹐也較容易懂﹐但是有其限制。對于Java interface的易懂﹐在文章中﹐并沒有說明。其主要即為「介面繼承」與「實作繼承」概念的差異。

「介面繼承」就是只繼承父類別的函數名稱﹐然后子類別一定會實作取代之。所以當我們以父類別的指標「多型」于各子類別時﹐由于子類別一定會實作父類別的多型函數﹐所以每個子類別的實作都不一樣﹐此時我們(使用父類別指標的人)并不知道此多型函數到底怎么完成﹐因之稱為「黑箱設計」。

「實作繼承」就是繼承父類別的函數名稱﹐子類別在實作時﹐也會用到父類別的函數實作。所以我們(使用父類別指標的人)知道此多型函數怎么完成工作﹐因為大概也跟父類別的函數實作差不多﹐因之稱為「白箱設計」。

套用的Java的interface上﹐我們發現﹐Java的interface就是介面繼承﹐因為Java interface只能定義函數名稱﹐無法定義函數實作﹐所以子類別必須用「implements」關鍵字來實作之﹐且每個實作同一介面的子類別當然彼此不知道對方如何實作﹐因此為一個黑箱設計。

Java的類別繼承則為實作繼承﹐子類別會用到父類別的實作(更正確地說應該是父類別有定義實作﹐所以子類別可能會使用到﹐即使不使用到也會遵循父類別實作的演算法)﹐所以父類別與子類別有一定程度的相關性﹔不像介面繼承﹐彼此只有函數名字剛好一樣而已。

介面繼承與實作繼承﹐應對至Java的interface﹑class﹑extends與implements關鍵字﹐很容易了解其含意。但是C++的繼承機制﹐似乎就沒有那么容易解釋清楚的!所以這就是[Ait86]文章中所表示的意思:C++多重機制比較復雜。

所以接下來我們將討論:

C++的多重繼承有什么功能﹐是Java的interface所達不到的?
在C++的ARM中﹐或是[Str94]的多重繼承章節里﹐皆提到了下述著名的例子:

#include <stdio.h>

class t1 {

public:

virtual void f() { puts("t1::f()"; }

virtual void g() { puts("t1::g()"; }

};

class t2 : public virtual t1 {

public:

virtual void g() { puts("t2::g()"; }

};

class t3 : public virtual t1 {

public:

virtual void f() { puts("t3::f()"; }

};

class t4 : public t2, public t3, public virtual t1 { ...};

void main() {

t4 *tt4=new t4; t2 *tt2=tt4; t3 *tt3=tt4;

tt4->f(); tt4->g(); tt2->f(); tt3->g();

}

// 程式輸出:

t3::f() t2::g() t3::f() t2::g()

程式3﹑C++著名的環狀繼承



由上例﹐我們發現﹐C++的多重繼承具有下列兩個特質是Java的interface所不能達到的功能。

圖1﹑C++的環狀多重繼承



C++的多重繼承可以形成環狀繼承關系﹐如圖1。但是不管是Java的繼承機制或是interface﹐都不容許有環狀的情況發生。換句話說﹐因為C++有virtual base的屬性的父類別﹐所有在多重繼承時﹐允許父類別被繼承兩次以上。但Java則完全不行。

本題中的tt4指標﹐轉成tt2指標后﹐執行f()函數時﹐仍然會正確地執行tt4中的f()函數﹐也就是t3::f()。我們可以發現﹐這種找函數的方式﹐是先找函數的正確名稱﹐再找函數所屬的類別的正確名稱。與Java的虛擬函數(或稱為abstract函數)不同。Java的是先找指標(或參考)所屬的正確類別名稱﹐再繼續找類別名稱下的正確函數名稱。

圖2﹑對于虛擬函數C++與Java的各別作法



對于第二點參考圖2。C++的虛擬函數﹐可以參考[Sou94]﹐C++編譯器對于每一個虛擬函數﹐均建立一個虛擬函數表與之應對﹐因為每一個虛擬函數在一個繼承樹可能有許多子類別實作之。因此在實際執行時﹐是先找虛擬函數表﹐然后再尋找與自己類別階層等級最靠近的那個函數實作。所以我們可以將一個父類別指標轉換成子類別后﹐反而仍執行母親那輩的虛擬函數。

而Java則不能透過interface執行上述功能。Java的抽象函數(abstract function)事實上就是C++的純虛擬函數(virtual function()=0)﹐沒有像C++可以有非純虛擬函數(就是子類別不一定要定義的虛擬函數)﹐所以很難執行上面復雜的例子。并且﹐Java的interface里的函數預設為抽象函數﹐也就是如果某類別實作此interface的話﹐interface里的所有函數都必須全部實作。因此在實際執行時﹐先決定interface物件轉型成某類別的物件﹐于是再執行該類別內的函數實作。

乍看之下﹐似乎C++的多重繼承功能較完整﹐那么:

Java的interface概念﹐是否可用C++的多重繼承模擬出來呢?
目前﹐在微軟的OLE技術中﹐確實是用C++的多重繼承模擬OLE中的interface概念﹐可以參考MFC中關于OLE COM的寫作。如下面的程式:

class CoSomeObject : public Iunknown, public Ipersiet {

// IUnknown methods

virtual DWORD AddRef(void);

virtual DWORD Release(void);

virtual HRESULT QueryInterface(REFILD, LPVOID FAR*);

//IPersist methods

virtual HRESULT GetCLASSID(LPCLSID pclsid);

};

(注:參見MFC Internals p.p 442)



然而﹐考慮以下的問題:Java interface的特色為﹐interface間可以繼承。但這里所謂的繼承﹐事實上只是子interface包括全部的父interface內的成員﹐無法像Java的類別或是C++的類別那樣﹐可以用子類別的新定義將父類別取代之。這也就是所謂的「介面繼承」與「實作繼承」的差別。換言之﹐Java interface繼承(注意﹐不是子類別implements父interface)只是一種「包含關系」而已﹐甚至包含不可以重復。所以﹐interface概念用在軟體模組間的介面定義便非常厲害﹐如CORBA的IDL便是。因此﹐Java interface仍然擁有許多優點﹐但如果我們要以C++的多重繼承模擬(或稱之為藉此學習Java interface概念)時﹐在C++這邊該如何映對呢?

我們以程式2的Java程式為主﹐觀察C++的模擬interface版﹐該如何映對。

#include <stdio.h>

class Test1 {

public:

virtual void f1()=0;

virtual void g1()=0;

};

class Test2 {

public:

virtual void f2()=0;

virtual void g2()=0;

};

class Test3 : public Test1, public Test2 {

public:

virtual void gg()=0;

};

class CTest : public Test3 {

public:

void f1() { puts("Test1::f1()"; }

void g1() { puts("Test1::g1()"; }

void f2() { puts("Test2::f2()"; }

void g2() { puts("Test2::g2()"; }

void gg() { puts("Test3::gg()"; }

};

void main() {

CTest ct; ct.f1();ct.f2();

ct.g1();ct.g2(); ct.gg();

}

// 程式輸出:

Test1::f1() Test2::f2() Test1::g1()

Test2::g2() Test3::gg()

程式4﹑C++對應的Java interface概念



由程式4可知﹐其實只要在每個類別中的每一個函數都宣告成純虛擬函數﹐則C++類別就變成Java interface概念了。

因此我們下一結論:C++的多重繼承功能較廣﹐Java的interface功能只是其中的一個子集。因為C++的虛擬函數可以有純虛擬函數﹐也可有非純虛擬函數﹐而Java只有抽象函數﹐所以功能模式少一種﹐自然能達到的效果較少一些。

但這并不代表Java的interface就比較差﹐因為interface的觀念較簡單﹐全部動態的抽象函數也正代表著Java為一純物件導向語言。與C++不同的是﹐C++考慮許多執行效率的問題﹐所以語言本身就變的較復雜化﹐同時C++的編譯器也是公認難寫的﹐多重繼承更是一大挑戰。Java的interface雖然好象少了一些功能﹐但其實那些功能在一般的程式設計中也很少碰到﹔并且觀念簡潔的Java interface﹐在設計軟體程式時更可以避免許多陷阱。總之﹐兩種程式語言機制是很難比較誰好誰壞的。

順帶一提的是:最近有一股新趨勢﹐就是物件導向程式語言所引導出來的新的概念﹐反過來引響物件導向分析與設計的基礎理論。如Java的interface或是微軟的OLE Interface﹐使得Booch﹑OMT整合方法&shy;&shy;UML﹐對軟體模組間的介面有了新的定義﹔或是C++的STL與template﹐促進許多學者對靜態的物件關系又有了新解等。■


溫馨提示:喜歡本站的話,請收藏一下本站!

本類教程下載

系統下載排行

網站地圖xml | 網站地圖html
主站蜘蛛池模板: 元氏县| 桑日县| 上思县| 遂昌县| 平陆县| 福鼎市| 聂荣县| 梨树县| 玉树县| 赤水市| 湘潭县| 石嘴山市| 基隆市| 会泽县| 临海市| 阿合奇县| 竹溪县| 江华| 密云县| 上饶县| 宜宾县| 东乡族自治县| 通道| 崇信县| 友谊县| 仙桃市| 崇州市| 白朗县| 中西区| 藁城市| 东辽县| 彭阳县| 宝兴县| 德清县| 太仆寺旗| 临夏市| 潼关县| 吉安市| 敖汉旗| 澄江县| 新疆|