青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

sherrylso

C++博客 首頁 新隨筆 聯系 聚合 管理
  18 Posts :: 0 Stories :: 124 Comments :: 0 Trackbacks

四、c++中的多態規則。
一) c++中函數動態綁定規則。
看下面的例子:

class Window
{

public:
  virtual 
void  oops()
  
{
    cout
<<"Window oops"<<endl;
  }

public:
  
int height;
  
int width;
}
;
class TextWindow : public Window
{

public:
  virtual 
void  oops()
  
{
    cout
<<"TextWindow oops"<<cursorLocation<<endl;
  }

public:
  
int cursorLocation;
}
;

main()
{
  Window win;
  Window
* tWin;
  TextWindow 
* tWinPtr;

  tWinPtr 
= new TextWindow;
  tWin 
= tWinPtr;
  
  win.oops();
  tWin
->oops();
}


類TextWindow繼承與類Window。我想程序運行的結果,大多數熟悉C++的人都會知道,
win.oops()最終調用的是父類oops函數,而tWin->oops()調用的是子類TextWindow的函數。
通過這個例子,我們先總結一下c++中的多態調用規則
第一、對于指針和引用類型,當消息調用的成員函數有可能被重寫時,最終被選擇調用的成員函數由消息接收者的動態類型確定(注意:在OO概念中,對某個對象成員函數進行調用,常常稱為給該對象發送消息,該對象就是消息的接收者)。
      如上例:tWin->oops(),由于tWin的動態類型是子類TextWindow,而不是Windows,所以tWin->oops()調用的是子類TextWindow的函數。
二、對于其它的變量,對虛擬函數調用綁定完全由該變量的靜態類型確定(即該變量的聲明),而不是該變量的真實類型確定。
     如上例:win.oops(),由于win的聲明類型為Window類,所以其結果調用的是父類oops函數。
二) 探討。
     接下來,我們要看的問題是,在c++中,為什么對于多態規則(或者說是動態函數綁定規則),做出了兩中不同的劃分,即:只有指針與引用類型,才進行函數的后期動態綁定,也就是多態。這或許也是許多c++初學者非常迷惑的地方。這種規則的不一致性,的確給c++的語法造成一定的復雜性。而這在Java,或者C#中是沒有的,后面我們會涉及到。
      我們先來看例子。 

void f()
{
  Window  win;
  Window
* tWinPtr;
  
  tWinPtr 
= new TextWindow;
  win     
= *tWinPtr;//what's problem happen
   
  win.oops(); 
//what's problem happen
  tWinPtr->oops();
}


      在這里,如果我們假設,c++的函數動態綁定規則是一致的,看看會發生什么問題???
      現在win被聲明為Window類型,然而其真實的類型為TextWindow(因為win=*tWinPtr),由于我們的假設,win現在是允許進行動態函數綁定的,所以當執行win.oops()時,實際上是調用子類TextWindow的成員函數。
     現在,我們有必要來審視一下win變量的內存布局。由于win變量是在棧上聲明的變量,其內存也是從棧進行分配(這是c++從c語言那里繼承過來的優良特質,從棧上分配內存空間比動態分配內存有更好的執行速度),c++標準規定:給win變量分配內存空間的大小,由其靜態的類型確定,即應該是Window類所使用的內存空間大小。在這種情況下,當執行win=*tWinPtr時,什么會發生?如下圖:

在默認的拷貝構造函數情況下,信息會出現丟失,這就是著名的slicing off現象。結果,變量cursorLocation在win的內存空間里丟失了。然而,問題是:在我們假設下,我們要求win.oops()導致TextWindow的成員函數調用,而在這個函數中,訪問到的cursorLocation變量是不存在!win.oops()調用將導致內存違例!
      到這里,我們可以總結一下:c++標準基于的其特定的內存分配規則,給出了以上,我們在前一節總結出的函數動態綁定規則。
三) 深入。
      當然,我們也可以說,c++也可以通過改變其內存分配規則,來給出一個一致性的函數動態綁定規則。比如:可以考慮在給win變量分配內存空間時,考慮其所有子類需求,然后分配最大數量的內存空間給win變量。這種做法可行性很差,對于編譯器而言,需要掃描整個程序(確定該類的所有子類),才能確定最大的內存空間是多少。在使用類庫或者框架的情況下,會引起整個類庫,框架的重新編譯,這是得不償失的!而這種做法,在oo的語言中,基本上是沒有的。這也是c++不得不基于其現有的內存管理機制,而對多態規則作出的不一致的解釋。
    對于這個c++現有的內存管理機制,我們如果從另外角度去理解的話,是很合理的。當win=*tWinPtr發生
時,我們可以類似地認為:好比一個float類型的數賦給了一個interger類型的變量,其結果當然是float的值被截斷了。
    我們再來看其它語言,Java(或者C#)是怎么解決的。
    最重要的一點是,在Java(C#)中只有引用的概念,所以在棧上聲明的類的變量,只需要分配一個指針大小的內存空間就行了,而不需要給該變量分配空間來保存變量內容本身,這其實就是我們現在看到的c++中指針和引用的情況。
    

 

posted on 2008-01-05 23:12 愛上龍卷風 閱讀(3201) 評論(8)  編輯 收藏 引用

Feedback

# re: c語法背后的故事(二) [未登錄] 2008-01-06 12:21 ZZZ
是有點晦澀  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) 2008-01-07 22:53 abettor.org
看來這個容易理解一些,呵呵。  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) [未登錄] 2008-01-10 11:10 Composition
sherrylso兄,
void f()
{
Window win;
Window* tWinPtr;

tWinPtr = new TextWindow;
win = *tWinPtr;//what's problem happen

win.oops(); //what's problem happen
tWinPtr->oops();
}
中win.oops(); 仍然會調用父類的方法,因為編譯器生成的拷貝構造函數不會拷貝vptr。希望你check一下。
這里僅僅切割了子對象,但是切割后的對象是合法的父對象,除非你的設計不合理,違反了LSP。  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) 2008-01-11 22:04 愛上龍卷風
@Composition
我的論述的前提是:“假設:c++的函數動態綁定規則是一致的“
搞不清楚你的觀點是什么?
  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) 2008-01-14 13:35 Composition
我的意思是不管子對象怎么切割,win.oops(); 永遠會調用父類的函數,絕不會因為切割調用子類的方法。既然不調用子類的方法,自然不會出錯。你可以在編譯器實驗一下,你這個例子會輸出Window oops xxx,沒有錯誤。
不管怎么假設,通過對象調用成員函數都是編譯時綁定,永遠不可能調用到子類的成員函數。
win = *tWinPtr;這句會調用Window的拷貝構造(編譯器生成),但是拷貝構造不會拷貝對象的vptr。而且就算拷貝了,通過對象調用成員函數也不通過vptr找vtable,而是直接調用對象類型對應到成員函數(編譯后成為全局函數)。你這里假設“c++的函數動態綁定規則是一致的”,但別忘了,vptr不拷貝,這是C++實現機制,怎么調用都是父類的成員函數,不會有多態。
如果你做出拷貝構造會拷貝vptr+對象調用會查找vtable的假設,那么你的論述應該合理。但是這么假設個人認為意義不大。  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) 2008-01-14 21:39 愛上龍卷風
@Composition
1) 首先,我要論述的是多態規則,不是只有C++有。很多面向對象的語言都有的特性。Java, C#, Smalltalk。你不必要局限于C++本身。
2) 其次,你說的,我都贊同,這就是c++的內存管理機制。
3) 基于c++的內存管理機制,推出了現有的C++多態規則。
4)我是在討論,C++語法為什么復雜的背后原因。也就是怎么去更好地理解現行的語法。
  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) 2008-01-14 21:41 愛上龍卷風
@Composition
再者,如果C++改變了現有的內存管理機制,即我提到的:可以考慮在給win變量分配內存空間時,考慮其所有子類需求,然后分配最大數量的內存空間給win變量。
是可以做到多態規則的一致性  回復  更多評論
  

# re: c++晦澀語法背后的故事(二) 2008-01-15 12:14 Composition
我明白你的意思了,不過我也沒有完全拘泥于C++,但是C++的多態實現確實與其他語言很不同。如Python,Ruby之類語言通過給類建立哈希表來實現多態。Java,C#之類應該是通過元數據。而且只有C++才有切割問題,其他語言在堆上分配就不存在切割了。
至于你的例子f()我覺得可以改成如下的例子更能說明問題,而且也不必做過多假設:
void f()
{
Window win;
TextWindow textWin;
Window* tWinPtr;

tWinPtr = new TextWindow;
memcpy(reinterpret_cast<char*>(tWinPtr) + 4,
reinterpret_cast<char*>(&win) + 4,
sizeof(win) - 4); //don't change vptr

tWinPtr->oops(); //what's problem happen
}
這個例子會發生錯誤,即使運行不出錯,邏輯也是錯的。
至于你對“可以考慮在給win變量分配內存空間時,考慮其所有子類需求,然后分配最大數量的內存空間給win變量。”的論述很透徹,我同意。  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久精品亚洲精品国产欧美kt∨| 亚洲手机视频| 久久人体大胆视频| 亚洲国产精品电影| 亚洲国产婷婷| 欧美精品久久99| 一区二区日韩精品| 亚洲欧美韩国| 一区二区三区在线视频观看| 亚洲国产裸拍裸体视频在线观看乱了| 欧美国产综合视频| 亚洲午夜激情网站| 亚洲欧美日韩专区| 亚洲国产电影| 一区二区电影免费观看| 国产欧美日韩在线播放| 欧美大胆a视频| 欧美日韩在线精品一区二区三区| 欧美一区二区啪啪| 美女精品自拍一二三四| 午夜影视日本亚洲欧洲精品| 久久这里只有精品视频首页| 一区二区三区视频观看| 欧美在线观看一二区| 一本色道久久综合狠狠躁篇的优点| 亚洲一区二区三区免费视频| 亚洲福利视频三区| 亚洲婷婷综合色高清在线| 在线观看欧美精品| 亚洲欧美国产精品专区久久| 亚洲欧洲免费视频| 欧美亚洲免费高清在线观看| 亚洲欧洲一区二区天堂久久| 欧美一区二区三区喷汁尤物| 一区二区三区不卡视频在线观看| 欧美一二三区精品| 美女网站在线免费欧美精品| 国产欧美一区二区三区在线老狼| 欧美成人精品福利| 国产人妖伪娘一区91| 亚洲最新在线| 亚洲国产高清在线观看视频| 欧美一级欧美一级在线播放| 亚洲一区二区三| 欧美精品一区在线播放| 免费日韩成人| 国产一区二区三区在线观看视频 | 曰本成人黄色| 午夜精品久久久久久久99水蜜桃| 一区二区三区欧美日韩| 麻豆精品传媒视频| 美女成人午夜| 国产综合欧美在线看| 亚洲视频在线观看一区| 日韩亚洲欧美成人| 欧美成人精精品一区二区频| 欧美大片第1页| 韩日精品在线| 久久av红桃一区二区小说| 欧美一区在线看| 国产精品久久久久久久久借妻| 亚洲精品国产精品国产自| 91久久久久久| 欧美国产欧美亚洲国产日韩mv天天看完整| 久久这里只精品最新地址| 国产视频一区二区三区在线观看| 亚洲欧美国产高清| 久久不见久久见免费视频1| 国产精品乱码久久久久久| 99re热这里只有精品视频| 日韩天堂av| 欧美日韩三级视频| 亚洲视频在线观看视频| 欧美亚洲一区在线| 国产日韩欧美二区| 久久偷窥视频| 亚洲第一主播视频| 亚洲午夜av在线| 国产精品久久久久久模特 | 亚洲国产99| 在线亚洲自拍| 国产精品乱子乱xxxx| 欧美一区二区三区在线观看| 免费看亚洲片| 亚洲黄色免费电影| 欧美午夜在线一二页| 亚洲欧美中文日韩v在线观看| 久久精品中文字幕一区| 亚洲高清自拍| 欧美日韩一视频区二区| 欧美一区二区在线播放| 亚洲国产高清自拍| 亚洲性av在线| 极品尤物一区二区三区| 欧美另类一区| 久久国产精品久久国产精品| 亚洲国产日韩欧美在线99| 欧美日韩国产一中文字不卡| 欧美a级片网站| 亚洲图片自拍偷拍| 一区二区三区亚洲| 欧美少妇一区| 久久精品亚洲热| 在线综合亚洲欧美在线视频| 久久综合影音| 亚洲一区二区三区在线观看视频 | 欧美一区二区在线看| 亚洲精品无人区| 久久野战av| 亚洲欧美日本国产专区一区| 亚洲黑丝一区二区| 国产午夜久久久久| 欧美色网在线| 蜜臀91精品一区二区三区| 午夜精品一区二区三区在线播放 | 欧美一区三区二区在线观看| 亚洲黄色三级| 好吊日精品视频| 欧美性生交xxxxx久久久| 免费看亚洲片| 久久久国产午夜精品| 亚洲制服欧美中文字幕中文字幕| 亚洲激情av在线| 欧美18av| 麻豆国产精品一区二区三区| 欧美一级专区| 在线综合亚洲欧美在线视频| 亚洲人成网站999久久久综合| 国户精品久久久久久久久久久不卡 | 欧美国产亚洲精品久久久8v| 久久精品99无色码中文字幕| 亚洲欧美一区二区三区久久| 亚洲图片欧美一区| 一区二区三区黄色| 日韩一二三区视频| 亚洲精品一二三| 最新成人在线| 亚洲人成在线观看一区二区| 最新日韩中文字幕| 亚洲人成网站999久久久综合| 亚洲第一毛片| 亚洲国产精品电影| 91久久精品国产91久久| 亚洲激情av| 亚洲片在线资源| 亚洲人成小说网站色在线| 亚洲欧洲精品天堂一级| 亚洲另类自拍| 在线一区亚洲| 小黄鸭精品aⅴ导航网站入口| 欧美亚洲午夜视频在线观看| 久久动漫亚洲| 久久青草福利网站| 欧美激情一区二区三区在线视频| 欧美激情视频一区二区三区不卡| 欧美国产日韩精品| 亚洲毛片av在线| 亚洲一区二区欧美日韩| 久久超碰97人人做人人爱| 久久久久一区二区三区| 欧美高清视频一区二区| 欧美性理论片在线观看片免费| 国产精品永久免费观看| 国模私拍一区二区三区| 最新亚洲激情| 亚洲欧美日韩精品| 久久综合久久88| 亚洲国产精品久久久| 一区二区三区毛片| 欧美一区二区在线免费播放| 免费的成人av| 欧美视频在线观看一区| 国产一区二区高清视频| 国产精品久久久亚洲一区| 欧美日韩视频在线第一区| 国产精品久久久久久亚洲调教 | 久久网站热最新地址| 欧美日韩视频在线| 韩国av一区二区三区在线观看| 亚洲精品国偷自产在线99热| 香蕉精品999视频一区二区 | 久久久久久九九九九| 亚洲国产精品ⅴa在线观看 | 亚洲国产欧美一区二区三区丁香婷| 亚洲特级毛片| 葵司免费一区二区三区四区五区| 欧美日韩在线观看视频| 在线看视频不卡| 欧美亚洲一区二区三区| 亚洲三级观看| 久久久亚洲精品一区二区三区 | 久久夜色精品国产噜噜av| 欧美性猛交xxxx免费看久久久| 亚洲丶国产丶欧美一区二区三区| 亚洲一区成人| 亚洲第一黄网| 久久国产精品久久w女人spa| 国产精品扒开腿爽爽爽视频| 日韩视频不卡| 欧美成人高清|