日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
C++和java多態(tài)的區(qū)別

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

創(chuàng)新互聯(lián)建站擁有十余年成都網(wǎng)站建設(shè)工作經(jīng)驗(yàn),為各大企業(yè)提供成都網(wǎng)站建設(shè)、成都做網(wǎng)站服務(wù),對(duì)于網(wǎng)頁設(shè)計(jì)、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、成都APP應(yīng)用開發(fā)、wap網(wǎng)站建設(shè)(手機(jī)版網(wǎng)站建設(shè))、程序開發(fā)、網(wǎng)站優(yōu)化(SEO優(yōu)化)、微網(wǎng)站、域名與空間等,憑借多年來在互聯(lián)網(wǎng)的打拼,我們?cè)诨ヂ?lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了很多網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、網(wǎng)絡(luò)營銷經(jīng)驗(yàn),集策劃、開發(fā)、設(shè)計(jì)、營銷、管理等網(wǎng)站化運(yùn)作于一體,具備承接各種規(guī)模類型的網(wǎng)站建設(shè)項(xiàng)目的能力。

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

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

  • 普通函數(shù)調(diào)用:具體調(diào)用哪個(gè)方法在編譯時(shí)間就可以決定(通過查找編譯器的符號(hào)表),同時(shí)在使用標(biāo)準(zhǔn)過程調(diào)用機(jī)制基礎(chǔ)上增加一個(gè)表示對(duì)象身份的指針(this指針)。
  • 虛函數(shù)調(diào)用:函數(shù)調(diào)用依賴于對(duì)象的實(shí)際類型,一般地說,對(duì)象的實(shí)際類型只能在運(yùn)行時(shí)間才能確定。虛函數(shù)一般要有兩個(gè)步驟來支持,首先每一個(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ù)而分配出來的。

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

  下面是C++和java的例子,不看后面的答案,你能夠正確說出它們的執(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,我們來分析一下兩個(gè)例子的執(zhí)行過程。

  首先看一下例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)造出來,當(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; 無關(guān)緊要。

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

  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)造出來,它的函數(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)確定了,就是說還沒有出生就已經(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++中的好。還是以例子說明吧:

  例子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ū)ο蠓椒ê貌缓媚?歡迎大家討論。


文章標(biāo)題:C++和java多態(tài)的區(qū)別
標(biāo)題路徑:http://www.5511xx.com/article/cdscdcc.html