偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

C++和java多態(tài)的區(qū)別

開發(fā) 開發(fā)工具
C++和java都具多態(tài)性,多態(tài)性其實(shí)就是方法調(diào)用的機(jī)制,也就是說(shuō)當(dāng)在編譯時(shí)無(wú)法確定一個(gè)對(duì)象的實(shí)際類型時(shí),應(yīng)當(dāng)能夠在運(yùn)行時(shí)基于對(duì)象的實(shí)際類型來(lái)決定調(diào)用的具體方法。本文主要介紹C++和java多態(tài)的區(qū)別。

  以前我有個(gè)錯(cuò)誤的觀點(diǎn):即使在C++java多態(tài)性的實(shí)現(xiàn)機(jī)制可能不同,但它們的表現(xiàn)形式應(yīng)該相同,也就是說(shuō)如果代碼結(jié)構(gòu)相同,那么執(zhí)行結(jié)果也應(yīng)該相同。可惜事與愿違,事情并不總是我想象中的那樣子,那么C++和java多態(tài)到底有何區(qū)別呢?

  首先我們提一下多態(tài)性的概念。根據(jù)Bjarne Stoustrup的說(shuō)法,多態(tài)性其實(shí)就是方法調(diào)用的機(jī)制,也就是說(shuō)當(dāng)在編譯時(shí)無(wú)法確定一個(gè)對(duì)象的實(shí)際類型時(shí),應(yīng)當(dāng)能夠在運(yùn)行時(shí)基于對(duì)象的實(shí)際類型來(lái)決定調(diào)用的具體方法(動(dòng)態(tài)綁定)。

  我們先來(lái)看一下在C++中的函數(shù)調(diào)用方式:

  • 普通函數(shù)調(diào)用:具體調(diào)用哪個(gè)方法在編譯時(shí)間就可以決定(通過(guò)查找編譯器的符號(hào)表),同時(shí)在使用標(biāo)準(zhǔn)過(guò)程調(diào)用機(jī)制基礎(chǔ)上增加一個(gè)表示對(duì)象身份的指針(this指針)。
  • 虛函數(shù)調(diào)用:函數(shù)調(diào)用依賴于對(duì)象的實(shí)際類型,一般地說(shuō),對(duì)象的實(shí)際類型只能在運(yùn)行時(shí)間才能確定。虛函數(shù)一般要有兩個(gè)步驟來(lái)支持,首先每一個(gè)類產(chǎn)生出一堆指向虛函數(shù)的指針,放在表格中,這個(gè)表格就叫虛函數(shù)表(virtual table);然后每一個(gè)類對(duì)象(class object)會(huì)添加一個(gè)指向相關(guān)虛函數(shù)表(virtual table)的指針,通常這個(gè)指針叫做vptr。

  在java中又是如何的呢?恩,區(qū)別還是滿大的。在java虛擬機(jī)中,類實(shí)例的引用就是指向一個(gè)句柄(handle)的指針,而該句柄(handle)其實(shí)是一對(duì)指針:其中一個(gè)指針指向一張表,該表格包含了對(duì)象的方法列表以及一個(gè)指向類對(duì)象(表示對(duì)象類型)的指針;另一個(gè)指針指向一塊內(nèi)存地址,該內(nèi)存是從java堆中為對(duì)象的數(shù)據(jù)而分配出來(lái)的。

  這時(shí),你可能會(huì)說(shuō),好象差不多嘛,不是都要維護(hù)一張函數(shù)表嗎?別急,讓我們先看一下例子,這樣你就能更好的理解它們之間的區(qū)別到底有多大了。

  下面是C++和java的例子,不看后面的答案,你能夠正確說(shuō)出它們的執(zhí)行結(jié)果嗎?

  例1:C++

  1.   class Base   
  2.   {   
  3.   public:   
  4.   Base()   
  5.   {   
  6.   init();   
  7.   }   
  8.   virtual ~Base() {}   
  9.   public:   
  10.   virtual void do_init()   
  11.   {   
  12.   init();   
  13.   }   
  14.   protected:   
  15.   virtual void init()   
  16.   {   
  17.   cout << "in Base::init()" << endl;   
  18.   }   
  19.   };   
  20.   class Derived : public Base   
  21.   {   
  22.   public:   
  23.   Derived()   
  24.   {   
  25.   init();   
  26.   }   
  27.   protected:   
  28.   void init()   
  29.   {   
  30.   cout << "in Derived::init()" << endl;   
  31.   }   
  32.   };   
  33.   int main(int argc, char* argv[])   
  34.   {   
  35.   Base* pb;   
  36.   pb = new Derived();   
  37.   delete pb;   
  38.   return 0;   
  39.   }      

  例2:java

  1. class Base   
  2.   {   
  3.   public Base()   
  4.   {   
  5.   init();   
  6.   }   
  7.   protected void init()   
  8.   {   
  9.   System.out.println("in Base::init()");   
  10.   }   
  11.   public void do_init()   
  12.   {   
  13.   init();  
  14.    }  
  15.    }   
  16.   class Derived extends Base   
  17.   {   
  18.   public Derived()   
  19.   {   
  20.   init();   
  21.   }   
  22.   protected void init()   
  23.   {   
  24.   System.out.println("in Derived::init()");  
  25.   }   
  26.   }   
  27.   public class Test   
  28.   {   
  29.   public static void main(String[] args)   
  30.   {   
  31.   Base base = new Derived();   
  32.   }   
  33.   }      

  例1的執(zhí)行結(jié)果是:

  1. in Base::init()   
  2. in Derived::init()      

  例2的執(zhí)行結(jié)果是:

  1. in Derived::init()   
  2. in Derived::init()  
  3.      

  看了結(jié)果后,你是馬上頓悟呢抑或是處于疑惑中呢?ok,我們來(lái)分析一下兩個(gè)例子的執(zhí)行過(guò)程。

  首先看一下例1(C++的例子):

  1. Base* pb; 只是聲明,不做什么。

  2. pb = new Derived();

  1) 調(diào)用new操作符,分配內(nèi)存。

  2) 調(diào)用基類(本例中是Base)的構(gòu)造函數(shù)

  3) 在基類的構(gòu)造函數(shù)中調(diào)用init(),執(zhí)行程序首先判斷出當(dāng)前對(duì)象的實(shí)際類型是Base(Derived還沒構(gòu)造出來(lái),當(dāng)然不會(huì)是Derived),所以這里調(diào)用的是Base::init()。

  4) 調(diào)用派生類(本例中是Derived)的構(gòu)造函數(shù),在這里同樣要調(diào)用init(),執(zhí)行程序判斷出當(dāng)前對(duì)象的實(shí)際類型是Derived,調(diào)用Derived::init()。

  3. delete pb; 無(wú)關(guān)緊要。

  例2(java的例子)的執(zhí)行過(guò)程:

  1. Base base = new Derived();

  1) 分配內(nèi)存。

  2) 調(diào)用基類(本例中是Base)的構(gòu)造函數(shù)

  3) 在基類的構(gòu)造函數(shù)中調(diào)用init(),執(zhí)行程序首先判斷出當(dāng)前對(duì)象的實(shí)際類型是Derived(對(duì),Derived已經(jīng)構(gòu)造出來(lái),它的函數(shù)表當(dāng)然也已經(jīng)確定了)所以這里調(diào)用的是Derived::init()。

  4) 調(diào)用派生類(本例中是Derived)的構(gòu)造函數(shù),在這里同樣要調(diào)用init(),執(zhí)行程序判斷出當(dāng)前對(duì)象的實(shí)際類型是Derived,調(diào)用Derived::init()。

  明白了吧。java中的類對(duì)象在構(gòu)造前(調(diào)用構(gòu)造函數(shù)之前)就已經(jīng)存在了,其函數(shù)表和對(duì)象類型也已經(jīng)確定了,就是說(shuō)還沒有出生就已經(jīng)存在了。而C++中只有在構(gòu)造完畢后(所有的構(gòu)造函數(shù)都被成功調(diào)用)才存在,其函數(shù)表和對(duì)象的實(shí)際類型才會(huì)確定。所以這兩個(gè)例子的執(zhí)行結(jié)果會(huì)不一樣。當(dāng)然,構(gòu)造完畢后,C++與java的表現(xiàn)就都一樣了,例如你調(diào)用Derived::do_init()的話,其執(zhí)行結(jié)果是:

  1.   in Derived::init() 

  個(gè)人認(rèn)為,java中的多態(tài)實(shí)現(xiàn)機(jī)制沒有C++中的好。還是以例子說(shuō)明吧:

  例子3:C++

  1.   class Base  
  2.   {  
  3.   public:  
  4.   Base()  
  5.   {  
  6.   init();  
  7.   }  
  8.   virtual ~Base() {}  
  9.   protected:  
  10.   int value;  
  11.   virtual void init()  
  12.   {  
  13.   value = 100;  
  14.   }  
  15.   };  
  16.   class Derived : public Base  
  17.   {  
  18.   public:  
  19.   Derived()  
  20.   {  
  21.   init();  
  22.   }  
  23.   protected:  
  24.   void init()  
  25.   {  
  26.   cout << "value = " << value << endl;  
  27.   // 做一些額外的初始化工作  
  28.   }  
  29.   };  
  30.   int main(int argc, char* argv[])  
  31.   {  
  32.   Base* pb;  
  33.   pb = new Derived();  
  34.   delete pb;  
  35.   return 0;  
  36.   } 

  例4:java

  1.   class Base   
  2.   {   
  3.   public Base()   
  4.   {   
  5.   init();   
  6.   }   
  7.   protected int value;   
  8.   protected void init()   
  9.   {   
  10.   value = 100;   
  11.   }   
  12.   }   
  13.   class Derived extends Base   
  14.   {   
  15.   public Derived()   
  16.   {   
  17.   init();   
  18.   }   
  19.   protected void init()   
  20.   {   
  21.   System.out.println("value = " + value);   
  22.   // 做一些額外的初始化工作   
  23.   }   
  24.   }   
  25.   public class Test   
  26.   {   
  27.   public static void main(String[] args)   
  28.   {   
  29.   Base base = new Derived();   
  30.   }   
  31.   }  

  例3的執(zhí)行結(jié)果是:

  1.   value = 10 

  例4的執(zhí)行結(jié)果是:

  1.   value = 0 
  2.   value = 0 

  從以上結(jié)果可以看出,java例子中應(yīng)該被初始化的值(這里是value)沒有被初始化,派生類根本不能重用基類的初始化函數(shù)。試問,如果初始化要在構(gòu)造時(shí)完成,并且初始化邏輯比較復(fù)雜,派生類也需要額外的初始化,派生類是不是需要重新實(shí)現(xiàn)基類的初始化函數(shù)呢?這樣的面向?qū)ο蠓椒ê貌缓媚?歡迎大家討論。

【編輯推薦】

  1. 實(shí)例演示C++多態(tài)的實(shí)現(xiàn)過(guò)程
  2. C++多態(tài)實(shí)現(xiàn)方法探討
  3. C++多態(tài)性基本概念講述
  4. 深入理解Java多態(tài)性
  5. 對(duì)Java程序多態(tài)性支持的改進(jìn)
  6. 深入Java核心 Java中多態(tài)的實(shí)現(xiàn)機(jī)制
責(zé)任編輯:韓亞珊 來(lái)源: 天極網(wǎng)開發(fā)頻道
相關(guān)推薦

2011-04-12 10:40:04

C++多態(tài)

2011-04-11 09:43:25

C++C

2011-07-15 00:47:13

C++多態(tài)

2011-06-21 15:00:07

JAVAC++

2011-12-25 15:35:05

ibmdwJavaC++

2024-04-29 07:48:04

C++FinalOverride

2010-01-28 14:38:36

C++和C#、Java

2020-06-17 12:22:44

C覆蓋重載

2022-07-01 11:56:54

C語(yǔ)言C++編程語(yǔ)言

2010-02-03 10:50:33

C++多態(tài)

2010-01-08 16:52:57

C++和C#

2010-11-22 16:01:08

C++多態(tài)

2010-01-28 15:22:12

C++嵌套類

2024-01-23 10:13:57

C++虛函數(shù)

2024-04-22 13:22:00

虛函數(shù)象編程C++

2011-07-13 18:00:51

CC++VC

2024-06-28 10:04:09

2009-10-22 09:17:16

C++ CLR

2024-02-26 12:13:32

C++開發(fā)編程

2010-02-05 16:07:52

C++多態(tài)覆蓋
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)