|
![]() |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
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?pC++的多重继续 根据[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?p利用Java的interface完成C++的多重继续功能 然而╋根据[Ait96]的文章显示╋他认为Java的interface比C++的多重继续好学很多╋也较轻易懂╋但是有其限制。对于Java interface的易懂╋在文章中╋并没有说明。其主要即为「介面继续」与「实作继续」概念的差异。 「介面继续」就是只继续父类别的函数名称╋然后子类别一定会实作取代之。所以当我们以父类别的指标「多型」于各子类别时╋由于子类别一定会实作父类别的多型函数╋所以每个子类别的实作都不相同╋此时我们(使用父类别指标的人)并不知道此多型函数到底怎么完成╋因之称为「黑箱设计」。 「实作继续」就是继续父类别的函数名称╋子类别在实作时╋也会用到父类别的函数实作。所以我们(使用父类别指标的人)知道此多型函数怎么完成工作╋因为大概也跟父类别的函数实作差不多╋因之称为「白箱设计」。 套用的Java的interface上╋我们发现╋Java的interface就是介面继续╋因为Java interface只能定义函数名称╋无法定义函数实作╋所以子类别必须用「implements」要害字来实作之╋且每个实作同一介面的子类别当然彼此不知道对方如何实作╋因此为一个黑箱设计。 Java的类别继续则为实作继续╋子类别会用到父类别的实作(更准确地说应该是父类别有定义实作╋所以子类别可能会使用到╋即使不使用到也会遵循父类别实作的演算法)╋所以父类别与子类别有一定程度的相关性?r不像介面继续╋彼此只有函数名字刚好相同而已。 介面继续与实作继续╋应对至Java的interface?pclass?pextends与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?pC++闻名的环状继续 由上例╋我们发现╋C++的多重继续具有下列两个特质是Java的interface所不能达到的功能。 图1?pC++的环状多重继续 C++的多重继续可以形成环状继续关系╋如图1。但是不管是Java的继续机制或是interface╋都不容许有环状的情况发生。换句话说╋因为C++有virtual base的属性的父类别╋所有在多重继续时╋答应父类别被继续两次以上。但Java则完全不行。 本题中的tt4指标╋转成tt2指标后╋执行f()函数时╋仍旧会准确地执行tt4中的f()函数╋也就是t3::f()。我们可以发现╋这种找函数的方法╋是先找函数的准确名称╋再找函数所属的类别的准确名称。与Java的虚拟函数(或称为abstract函数)不同。Java的是先找指标(或参考)所属的准确类别名称╋再继承找类别名称下的准确函数名称。 图2?p对于虚拟函数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?pC++对应的Java interface概念 由程式4可知╋其实只要在每个类别中的每一个函数都宣告成纯虚拟函数╋则C++类别就变成Java interface概念了。 因此我们下一结论:C++的多重继续功能较广╋Java的interface功能只是其中的一个子集。因为C++的虚拟函数可以有纯虚拟函数╋也可有非纯虚拟函数╋而Java只有抽象函数╋所以功能模式少一种╋自然能达到的效果较少一些。 但这并不代表Java的interface就比较差╋因为interface的观念较简朴╋全部动态的抽象函数也正代表着Java为一纯物件导向语言。与C++不同的是╋C++考虑许多执行效率的问题╋所以语言本身就变的较复杂化╋同时C++的编译器也是公认难写的╋多重继续更是一大挑战。Java的interface虽然好象少了一些功能╋但其实那些功能在一般的程式设计中也很少遇到?r并且观念简洁的Java interface╋在设计软体程式时更可以避免许多陷阱。总之╋两种程式语言机制是很难比较谁好谁坏的。 顺带一提的是:最近有一股新趋势╋就是物件导向程式语言所引导出来的新的概念╋反过来引响物件导向分析与设计的基础理论。如Java的interface或是微软的OLE Interface╋使得Booch?pOMT整合方式­­UML╋对软体模组间的介面有了新的定义?r或是C++的STL与template╋促进许多学者对静态的物件关系又有了新解等。■ 返回类别: 教程 上一教程: [java技术] Java常用术语解释 下一教程: 细说Java之util类 您可以阅读与"JAVA 的interface观念 与C++ 多重继续的比较"相关的教程: · java做的比较完善的FTP连接上传下载文件 · Java中数组之间的比较 · ASP与JSP的比较 · 纪念在chinaasp积分过一百呕心原创一篇(Java 中对文件的读写操作之比较)拿分好难呀,555~~~,不知道那... · JAVA中对文件的读写操作之比较 |
![]() ![]() |
快精灵印艺坊 版权所有 |
首页![]() ![]() ![]() ![]() ![]() ![]() ![]() |