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

cexer

cexer
posts - 12, comments - 334, trackbacks - 0, articles - 0
  C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

GUI框架:談?wù)効蚣埽瑢憣懘a

Posted on 2009-11-15 18:09 cexer 閱讀(12417) 評(píng)論(176)  編輯 收藏 引用 所屬分類: GUIpattern
轉(zhuǎn)帖請(qǐng)注明出處 http://m.shnenglu.com/cexer/archive/2009/11/15/100988.html

1 開篇廢話

  我喜歡用C++寫 GUI 框架,因?yàn)槟欠N成就感是實(shí)實(shí)在在地能看到的。從畢業(yè)到現(xiàn)在寫了好多個(gè)了,都是實(shí)驗(yàn)性質(zhì)的。什么拳腳飛刀毒暗器,激光核能反物質(zhì),不論是旁門左道的陰暗伎倆,還是名門正派的高明手段,只要是 C++ 里有的技術(shù)都試過(guò)了。這當(dāng)中接觸過(guò)很多底層或是高級(jí)的技術(shù),像編譯時(shí)類型檢測(cè),運(yùn)行時(shí)代碼修改等等,按實(shí)現(xiàn)的不同 GUI 涉及的東西是沒有邊際的。從最開始模仿 MFC,ATL 那樣的實(shí)現(xiàn)學(xué)到很多東西,然后開始看一些開源的著名的 GUI 框架,像 MFC,WTL,SmartWin++,win32gui,jlib2 ,VCF 獲得很多啟發(fā),到現(xiàn)在似乎有一種已看盡天下 GUI 的感覺。在學(xué)習(xí)別人的框架和自己的實(shí)現(xiàn)過(guò)程中,真真實(shí)實(shí)地感覺自己成長(zhǎng)了不少,也有很多感悟。

  寫到這,我作為輪子制造愛好者,在這里向那些喊著"不要重復(fù)制造輪子的"批評(píng)家們承認(rèn)錯(cuò)誤。在有那么多好的輪子的情況下,我不值得浪費(fèi)地球資源,浪費(fèi)時(shí)間精力來(lái)自己手工重復(fù)打造。但是不值得歸不值得,在值得和喜歡之間我還是選擇后者。并且人生在世,什么才是值得?我覺得不是拯救人類,為世界和平做貢獻(xiàn),也不是努力奮斗,為地球人民謀福利,而是簡(jiǎn)單地做自己喜歡的事。

  寫過(guò)的那些代碼很多都消失在硬盤的海洋里了,但那些挑燈苦想來(lái)的感悟還在。在它們也消失之前,我想利用空閑時(shí)間把這些覺得有點(diǎn)用處的經(jīng)驗(yàn)寫出來(lái),正好這個(gè)博客也已經(jīng)快一年沒更新了。另外也算是對(duì)那些發(fā)我郵件的朋友的回應(yīng)。

  我的想法是用一系列日志,按照實(shí)現(xiàn)一個(gè) GUI 框架的具體思維遞進(jìn)過(guò)程來(lái)闡述實(shí)現(xiàn)一個(gè) GUI 框架的具體思維遞進(jìn)過(guò)程。這樣說(shuō)好像有點(diǎn)遞歸,簡(jiǎn)單地解釋就是這一系列日志不是想用《記憶碎片》那樣錯(cuò)亂的敘述方式來(lái)說(shuō)明一個(gè)多有意思的故事,而是盡量簡(jiǎn)單自然地記錄一下寫 GUI 框架過(guò)程中我的思考。這個(gè)遞進(jìn)過(guò)程也就是實(shí)現(xiàn)一個(gè) GUI 框架的過(guò)程,一系列日志之后,我們將會(huì)看到一個(gè)長(zhǎng)得漂亮眼,極富彈性,能干又節(jié)約的 GUI 框架。

  雖然寫的內(nèi)容都是在 Windows 的 GUI 系統(tǒng)之上,但其原理是觸類旁通的,其它基于消息的 GUI 系統(tǒng)也都大同小異。所用的代碼也都是闡述原理的,自知絕對(duì)達(dá)不到商業(yè)巨作的水準(zhǔn),所以請(qǐng)不要一上來(lái)就批判,要知道我只是想分享而已。之所以先這樣說(shuō)一下,是很害怕那種一上來(lái)就"怎么不跨平臺(tái)啊?","怎么都還看得到HWND啊?","怎么不能用成員函數(shù)處理消息啊?"的同志。不喜歡站在高處指著別人的天靈蓋說(shuō)話的人。要知道車輪也是一步步造出來(lái)的,不要一開始就想載著MM在高速路上飆豪車像少年啦飛馳。

  我認(rèn)為寫技術(shù)博客有三種境界,一種是一直在那繪聲繪色地描述自己的魚有多可口多美味,讓讀者只能垂涎興嘆,一種是授人以魚的人,悶頭就擺出來(lái)各種生猛海鮮,讓讀者難以消化,還有一種境界是授人以漁,怎么釣魚怎么煮魚都細(xì)細(xì)地教給讀者。讀博客的人有兩個(gè)境界,一種是只吃魚的,一上來(lái)就只要代碼,一種是學(xué)打魚的,想知其然更想知其所以然。讀博客時(shí)我努力做學(xué)打魚的類型,自己寫博客時(shí)我會(huì)努力做到授人以漁的境界。

  另外要說(shuō)明的是,同樣作為塵世中的一個(gè)渺小個(gè)體,我大多數(shù)時(shí)候也是在為生存而奔波勞累著的。除此之外剩余的大多時(shí)候,更是要玩游戲,K歌,看電影,陪MM,吃喝玩樂。再剩余用來(lái)寫這個(gè)的時(shí)候不是很多,有可能這一系列日志一夜寫就,也有可能增刪五年披閱十載,孩子都叫爸了還沒完成。所以請(qǐng)大家不要對(duì)這個(gè)博客抱很大的期待,就當(dāng)我是路邊街頭的表演,你打醬油經(jīng)過(guò)時(shí)偶爾瞟過(guò)來(lái)一眼就好了。

  要說(shuō)的廢話終于說(shuō)完了,下面開始正題。

2 基本概念

  基于消息的 GUI 框架的封裝,一切都圍繞消息展開。復(fù)雜的框架設(shè)計(jì),明確了需求之后,第一步首先是劃分模塊。所以,要闡述一個(gè)設(shè)計(jì)過(guò)程,第一步也應(yīng)該是先說(shuō)清最基本的概念和模塊劃分,而不是一上來(lái)就用廣義相對(duì)論把讀者全部放倒。GUI 框架是干什么的當(dāng)然是地球人都知道的,但 GUI 框架沒有什么已經(jīng)劃分的標(biāo)準(zhǔn)概念,我是按照設(shè)計(jì)的需要來(lái)劃分的。如果把 GUI 框架看作一個(gè)單位,那么這個(gè)單位里最重要的角色有這幾個(gè):

  • 消息發(fā)送者(message sender)
  • 消息監(jiān)聽者(message listener)
  • 消息檢查者(message checker)
  • 消息處理者(message handler)
  • 消息分解者(message cracker)
  • 消息映射者(message mapper)

  下面分別說(shuō)明。

2.1 消息發(fā)送者和消息(message sender,message) 

  消息發(fā)送者其實(shí)只是在這里友情客串一下,它不在框架設(shè)計(jì)之內(nèi),由操作系統(tǒng)扮演這個(gè)勞苦功高的角色,它的工作是將消息發(fā)送到消息監(jiān)聽者。在這里面隱含了一下最重要的角色,消息。其實(shí)剩余的所有角色說(shuō)到底也只是死跑龍?zhí)椎模嬲I(lǐng)銜的是消息本身,比如窗口大小改變了的消息,按鈕被點(diǎn)擊了的消息等等,所有人都高舉旗幟緊密團(tuán)結(jié)在它周圍進(jìn)行工作。但消息本身只是一個(gè)很簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu),因?yàn)樵購(gòu)?fù)雜的 GUI 系統(tǒng),它的消息也不過(guò)是幾個(gè)參數(shù),所以框架的實(shí)現(xiàn)重點(diǎn)在其它的角色。在此之前簡(jiǎn)單地封裝一下消息,一個(gè)最簡(jiǎn)單的封裝可能是這樣:

   1: // 消息封裝類
   2: class Message
   3: {
   4: public:
   5:     Message( UINT id_=0,WPARAM wparam_=0,LPARAM lparam_=0 )
   6:         :id( id_ )
   7:         ,wparam ( wparam_ )
   8:         ,lparam ( lparam_ )
   9:         ,result ( 0 )
  10:     {}
  11:
  12:     UINT      id;
  13:     WPARAM    wparam;
  14:     LPARAM    lparam;
  15:     LRESULT   result;
  16: };

  就這樣的我們的公司已經(jīng)有了核心角色了。從概念上講,我們的這個(gè)基于消息的 GUI 框架已經(jīng)完成了 99% 。然后我們可以以它為中心,按功能劃分進(jìn)行詳細(xì)討論,一步步完成那剩余的 1% 的極富創(chuàng)意和挑戰(zhàn)的工作。在此之前,先得簡(jiǎn)單解釋一下這幾個(gè)角色都各是什么概念。消息傳送者如上所述,將不在討論范圍內(nèi)。

2.2 消息監(jiān)聽者(message listener) 

  消息監(jiān)聽者完成的工作是從操作系統(tǒng)接收到消息,消息是從這里真正到達(dá)了框架之內(nèi)。最簡(jiǎn)單的消息監(jiān)聽者是一個(gè)提供給操作系統(tǒng)的回調(diào)函數(shù),比如在 Windows 平臺(tái)上這個(gè)函數(shù)的樣子是這樣:

   1: //我是最質(zhì)樸的消息接收者
   2: LRESULT CALLBACK windowProc( HWND window,UINT id,WPARAM wparam,LPARAM lparam );

  一個(gè)好 GUI 框架當(dāng)然不能赤祼祼地使用這個(gè)東西,我們要在此之上進(jìn)行面向?qū)ο蟮姆庋b。消息監(jiān)聽者能想到的最自然的封裝模式是觀察者模式(Observer),這樣的模式下的監(jiān)聽者實(shí)現(xiàn)看起來(lái)像這個(gè)樣子:

   1: //我是一個(gè)漂亮的觀察者模式的消息監(jiān)聽者
   2: class MessageListener
   3: {
   4: public:
   5:     virtual LRESULT onMessage( Message* message ) = 0;
   6: };
   7:
   8: //監(jiān)聽者這樣工作
   9: MessageListener* listener;
  10: window->addListener( listener );
  11:

  jlib2 和 VCF 的實(shí)現(xiàn)就是這種模式。但現(xiàn)實(shí)當(dāng)中大多數(shù)框架沒有使用這種模式,比如 SmartWin++ 和 win32gui ,甚至沒有使用任何模式比如 MFC 和 WTL 。我想它們所以不采用觀察者模式,有些是因?yàn)榭蚣苷w實(shí)現(xiàn)的牽制,有的則可能是因?yàn)闆]能解決某些技術(shù)問(wèn)題。我們的 GUI 框架將實(shí)現(xiàn)觀察者模式的消息監(jiān)聽者,所以這些問(wèn)題我們后面也會(huì)遇到,到時(shí)候再詳述。

2.3 消息檢查者(message checker)

  消息檢查者完成的工作很簡(jiǎn)單。當(dāng)收到消息的時(shí)候,框架調(diào)用消息檢查者檢查這個(gè)消息是否符合某種條件,如果符合,則框架再調(diào)用消息處理者來(lái)處理這個(gè)消息,所以有點(diǎn)類似一個(gè)轉(zhuǎn)換者,輸入(消息),輸出一個(gè)(是/否)的值。最簡(jiǎn)單的檢查者可能就是一個(gè)消息值的比較,比如:

   1:
   2: /最簡(jiǎn)單的消息檢查者
   3: essage.id == /*消息值*/
   4:
   5: /比如
   6: essage.id == WM_CREATE

  展開MFC 和 ATL 的消息映射宏,可以看到它們的消息檢查就是用堆積起來(lái)的消息值比較語(yǔ)句完成。這就是消息檢查者最原始最自然最簡(jiǎn)單的實(shí)現(xiàn)方式,但這種方式缺陷太多。我們的框架將實(shí)現(xiàn)一個(gè)自動(dòng)化,具有擴(kuò)展性的消息檢查者,后文詳細(xì)討論。

2.4 消息處理者(message handler)

  消息處理者是我們最終的目的。GUI 框架所做的一切努力都只是前期的準(zhǔn)備,直到消息處理者運(yùn)行起來(lái)那一刻,整個(gè)公司才算是真正地運(yùn)轉(zhuǎn)起來(lái)了。消息處理者的具體實(shí)現(xiàn)可能是自由函數(shù),成員函數(shù)或者其它可調(diào)用體,甚至可以是外部腳本,處理完畢可能需要給操作系統(tǒng)返回一個(gè)結(jié)果。最簡(jiǎn)單的消息處理者可以就是條語(yǔ)句,比如:

   1: //消息處理
   2: alert( "窗口創(chuàng)建成功了!" );
   3:
   4: //返回結(jié)果
   5: message.result = TRUE;

  上面代碼中"顯示消息框"的動(dòng)作就是一個(gè)消息處理,以上兩行代碼可視為消息處理者。最常見的消息處理者是函數(shù),比如:

   1: //消息處理
   2: _handleCreated( message );

  代碼中的函數(shù) _handleCreated 就是一個(gè)典型的消息處理者。消息處理者的實(shí)現(xiàn)難處在于,既要支持多樣性的調(diào)用接口,又要支持統(tǒng)一的處理方式。我們的框架將實(shí)現(xiàn)一個(gè)支持自由函數(shù),成員函數(shù),函數(shù)對(duì)象,或者其它可調(diào)用體的消息處理者,并且這些可調(diào)用體可以具有不同參數(shù)列表。后文將進(jìn)行消息處理者的詳細(xì)討論。

  在這里有必要再說(shuō)明一下。一個(gè)判斷語(yǔ)句的大括號(hào)之前(判斷部分)是消息檢查的動(dòng)作,大括號(hào)之內(nèi)(執(zhí)行部分)是實(shí)際的消息處理。因此一個(gè)判斷語(yǔ)句雖簡(jiǎn)單,卻包含消息檢查者和消息處理者,以及另外一個(gè)神秘的部分(見后文),一共三個(gè)部分。代碼像這樣:

   1: if ( //消息檢查者 )
   2: {
   3:     //消息處理者
   4: }

  比如下面的代碼:

   1: // message.id == WM_CREATE 是消息檢查者
   2: // _handleCreated( message )是消息處理者
   3:
   4: if ( message.id == WM_CREATE )
   5: {
   6:     _handleCreated( message );
   7: }
   8:

2.5 消息分解者(message cracker)

  消息分解者是為消息處理者服務(wù)的。不同的消息處理者需要的信息肯定不一樣,比如一個(gè)繪制消息(WM_PAINT)的消息處理者可能需要的是一個(gè)圖形設(shè)備的上下文句柄(HDC),而一個(gè)按鈕點(diǎn)擊消息(BN_CLICK)的消息處理者則可能需要的是按鈕的ID,它們都不想看到一個(gè)赤祼祼的消息杵在那里。從消息中分解出消息攜帶的具體信息,這就是消息分解者的工作。最簡(jiǎn)單的消息分解者可能是一個(gè)強(qiáng)制轉(zhuǎn)換,比如:

   1: // WM_CREATE 消息參數(shù)分解
   2: CREATESTRUCT* createStruct = (CREATESTRUCT*)message.lparam;
   3:
   4: // WM_SIZE 消息參數(shù)分解
   5: long width  = LOWORD( message.lparam );
   6: long height = HIWORD( message.lparam );

  上面的的代碼雖然簡(jiǎn)單但 100% 完成了消息分解的任務(wù),所以它也是合格的消息分解者。我的框架將實(shí)現(xiàn)一個(gè)自動(dòng)化,可擴(kuò)展的消息分解者。后文將以此為目標(biāo)進(jìn)行詳細(xì)討論。

2.6 消息映射者(message mapper)

  消息映射者是最直接與框架外部打交道的部分,顧名思義,它的工作就是負(fù)責(zé)將消息檢查者與消息處理者映射起來(lái)。最簡(jiǎn)單的映射者可以是一條判斷語(yǔ)句,這個(gè)判斷語(yǔ)句,如代碼所示:

   1: // if 語(yǔ)句的框架就是一個(gè)消息映射者
   2:
   3: // 消息映射者
   4: if ( /*消息檢查者*/ )
   5: {
   6:     /*消息處理者*/
   7: }
   1: // if 語(yǔ)句將消息檢查者 message.id==WM_CREATE 和消息處理者 _handleCreated(message) 聯(lián)系起來(lái)了
   2: if ( message.id == WM_CREATE )
   3: {
   4:     _handleCreated( message );
   5: }

  上面的代碼 的if 語(yǔ)句中,判斷的部分是消息檢查者,執(zhí)行的部分是消息處理者。if 語(yǔ)句把這兩個(gè)部分組成了一個(gè)映射,這是最簡(jiǎn)單的消息映射者。到這里可以發(fā)現(xiàn),這個(gè)簡(jiǎn)單的 if 語(yǔ)句有多不簡(jiǎn)單。它低調(diào)謙遜但獨(dú)自地完成了很多工作,就像公司的小張既要寫程序,又要掃地倒茶,還義務(wù)地給女同事講笑話。MFC 和 WTL 的消息映射宏展開就是這樣的 if 語(yǔ)句。像 jlib2 那樣的框架,雖然處理者都虛函數(shù),但在底層也是用 if 語(yǔ)句判斷消息然后來(lái)進(jìn)行調(diào)用的。當(dāng)然還有華麗一點(diǎn)的消息映射者,像這樣:

   1: // 華麗一點(diǎn)的消息映射者
   2: window.onCreated( &_handledCreated );

  這個(gè) onCreated 也是一個(gè)消息映射者,在它的內(nèi)部把 WM_CREAE 消息和 _handleCreated 函數(shù)映射到一起,這種方式最有彈性,但實(shí)現(xiàn)起來(lái)也比宏和虛函數(shù)都要困難得多。SmarWin++ 就是使用的這種方式,它的消息映射者版本看起來(lái)一樣的陽(yáng)光帥氣,但內(nèi)部實(shí)現(xiàn)有些細(xì)節(jié)稍嫌猥瑣。我們的 GUI 框架將實(shí)現(xiàn)一個(gè)看起來(lái)更美,用起來(lái)很爽的消息映射者像這個(gè)樣子:

   1: // 將消息處理者列表清空,設(shè)置為某個(gè)處理者
   2: // 可以這樣
   3: window.onCreated  = &_handleCreated;
   4: // 或者這樣
   5: window.onCreated.add( &_handleCreated );
   6:
   7: // 在消息處理者列表中添加一個(gè)處理者
   8: // 可以這樣
   9: window.onCreated += &_handleCreated;
  10: // 或者這樣
  11: window.onCreated.add( &_handleCreated );
  12:
  13: // 清空消息處理者列表
  14: // 可以這樣
  15: window.onCreated --;
  16: // 或者這樣
  17: window.onCreated.clear();

  值得說(shuō)一下,這種神奇的映射者是接近零成本的,它沒有數(shù)據(jù)成員沒有虛函數(shù)什么都沒有,就是一個(gè)簡(jiǎn)單的空對(duì)象。就像傳說(shuō)中的工作能力超強(qiáng),但卻不拿工資,不泡公司MM,甚至午間盒飯也不要的理想職員。在后文當(dāng)中會(huì)具體詳述這個(gè)消息映射者的實(shí)現(xiàn)。

3 結(jié)尾廢話

  到目前為止我們的框架已經(jīng)完成了 99% 。下篇準(zhǔn)備開始寫最簡(jiǎn)單的消息檢查者,但說(shuō)實(shí)話我也不知道下一篇什么時(shí)候開始。看看上一篇日志,竟然是一年前寫的,這一年內(nèi)發(fā)生的事情很多,但自己渾渾噩噩地的好像一眨眼就到了現(xiàn)在,看著 CPPBLOG 上的好多其它兄弟出的很多很有水準(zhǔn)的東西,心里真是慚愧。昨天看了《2012》,現(xiàn)在心里還殘留有那種全世界在一間瞬間灰飛煙滅的震撼,2012年也不遠(yuǎn)了,我也趕緊在地球毀滅之前加把油把這些日志寫完了吧。不管怎么樣,今天哥先走了,請(qǐng)不要迷戀哥。

評(píng)論共2頁(yè): 1 2 

Feedback

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:21 by OwnWaterloo
占個(gè)沙發(fā),對(duì)這個(gè)很好奇:

"值得說(shuō)一下,這種神奇的映射者是接近零成本的,它沒有數(shù)據(jù)成員沒有虛函數(shù)什么都沒有,就是一個(gè)簡(jiǎn)單的空對(duì)象。就像傳說(shuō)中的工作能力超強(qiáng),但卻不拿工資,不泡公司MM,甚至午間盒飯也不要的理想職員。"

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:24 by cexer
@OwnWaterloo
謝謝沙發(fā),后面會(huì)詳細(xì)說(shuō)說(shuō)這個(gè)消息映射者的實(shí)現(xiàn)

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:38 by WXX
如果單就消息的派發(fā),那么一個(gè)gui框架可以很容易實(shí)現(xiàn),但是要很好的管理窗口之間的關(guān)系,很好的處理鍵盤加速鍵,鼠標(biāo)等這些交互就麻煩了,考慮消息的過(guò)濾等。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:40 by OwnWaterloo
從這2行代碼來(lái)說(shuō):
window.onCreated.add( &_handleCreated );
window.onCreated.clear();


從UINT message 到 onCreate 的這個(gè)分派(dispatch)過(guò)程,無(wú)論怎樣都必定是一個(gè)運(yùn)行時(shí)解析過(guò)程。
無(wú)論使用何種C++高級(jí)技巧,也不可能讓它變?yōu)榫幾g時(shí)dispatch。
因?yàn)閙essage是一個(gè)運(yùn)行時(shí)才能得到的值……
只是,這個(gè)dispatch的工作,可能不是由window所在的class完成,而是其他某個(gè)層次完成。
總之,這個(gè)層次一定存在,這個(gè)工作(運(yùn)行時(shí)dispatch)一定免不了。
我猜得對(duì)嗎……


接下來(lái),框架將message 分派到onXXX之后,客戶再將onXXX轉(zhuǎn)發(fā)(forwarding)自己的handler這個(gè)過(guò)程,我相信是可以編譯時(shí)確定的。
——因?yàn)槲铱催^(guò)你以前的一些實(shí)現(xiàn)~_~

但是,編譯時(shí)確定,就意味著運(yùn)行時(shí)不可更改。
如果要運(yùn)行時(shí)可更改 —— 如上面2行代碼 —— 就一定需要一個(gè)"可調(diào)用體"(callable)來(lái)作handler的占位符(placeholder)。
是這樣嗎?
而C/C++里面,完全不占用一點(diǎn)空間的callable…… 是不存在的,對(duì)吧?


所以我很好奇window是如何零成本完成映射與轉(zhuǎn)發(fā),并且是一個(gè)空對(duì)象的。
映射肯定需要在某個(gè)地方做,可能不是window。
運(yùn)行時(shí)可更改轉(zhuǎn)發(fā)目的地而不使用數(shù)據(jù), 好像…… 太不可思議了……


# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:48 by cexer
@OwnWaterloo
這個(gè)消息映射者的實(shí)現(xiàn)沒有數(shù)據(jù)成員,沒有虛函數(shù)存在,它其實(shí)就是一個(gè)調(diào)用,所以它也是有時(shí)間成本的。是的,所以我說(shuō)是接近0成本,而不是真正的0成本。畢竟世界上沒有那樣傳說(shuō)的員工。但如果好的編譯期可以輕松優(yōu)化掉這個(gè)小小調(diào)用。

你說(shuō)不可思議,那倒沒到那個(gè)境界哈。你可以看看《Imperfect C++》當(dāng)中的method_property的實(shí)現(xiàn),跟那個(gè)很類似,不過(guò)他的實(shí)現(xiàn)不符合C++標(biāo)準(zhǔn),應(yīng)范圍有限。

用這種消息映射者的方式,我也實(shí)現(xiàn)了值主義的屬性,比如:
window.size = Size( 100,100 );
Size size = window.size;

從理論上來(lái)說(shuō),也接近0成本的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:53 by cexer
@OwnWaterloo
你說(shuō)的“接下來(lái),框架將message 分派到onXXX之后,客戶再將onXXX轉(zhuǎn)發(fā)(forwarding)自己的handler這個(gè)過(guò)程,我相信是可以編譯時(shí)確定的。
——因?yàn)槲铱催^(guò)你以前的一些實(shí)現(xiàn)~_~”

你說(shuō)的這個(gè)是以前另一個(gè)版本的框架了,跟這個(gè)完全不一樣了哦。你看那份代碼,它的消息映射是編譯期自動(dòng)進(jìn)行的,映射者,檢查者,分解者三個(gè)角色都是由一個(gè)東西全部完成的。我將寫的這個(gè)版本不一樣,是完全分離的實(shí)現(xiàn),沒有那種編譯期映射的功能,但運(yùn)行時(shí)映射可以獲得更大的擴(kuò)展性。

可惜啊,以前那個(gè)版本的框架代碼我已經(jīng)找不到了。你那里有?

你說(shuō)的“以我很好奇window是如何零成本完成映射與轉(zhuǎn)發(fā),并且是一個(gè)空對(duì)象的。映射肯定需要在某個(gè)地方做,可能不是window。運(yùn)行時(shí)可更改轉(zhuǎn)發(fā)目的地而不使用數(shù)據(jù), 好像…… 太不可思議了……”

看來(lái)你有點(diǎn)誤會(huì)我的意思了,肯定內(nèi)存當(dāng)中是有一個(gè) std:map 之類的映射數(shù)據(jù)存在的。我說(shuō)的0成本指的是 window.onCreated 這個(gè)成員的實(shí)現(xiàn)。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:57 by OwnWaterloo
@cexer
哦 原來(lái)是property模擬。

window.size
window.onCreated
是一個(gè),呃,代理(proxy)對(duì)象?

size是一個(gè)代理,有一個(gè)=操作符和轉(zhuǎn)換函數(shù):
operator=(const Size& s) {
this->window->setSize(s);
}
operator Size() const {
return this->window->getSize();
}

這個(gè)代理對(duì)象也是要占空間的吧?


呃…… 還是等你的源代碼與分析吧…… 不瞎猜了……
看來(lái)你也是難得抓到一個(gè)更新blog的閑暇……

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 18:58 by OwnWaterloo
@cexer
沒有完整的,就是你blog上發(fā)的一些片段……

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 19:01 by cexer
@OwnWaterloo
你說(shuō)“哦 原來(lái)是property模擬。”
嗯就是這樣的。

你說(shuō)“這個(gè)代理對(duì)象也是要占空間的吧?”
理論上來(lái)說(shuō)不要占空間的,但實(shí)際是占用一個(gè)字節(jié)的。因?yàn)镃++標(biāo)準(zhǔn)規(guī)定不允許存在0空間占用的成員變量,因?yàn)槟菚?huì)造成 &object.member1,&object.memeber2 兩個(gè)地址完全相同的情況。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 19:07 by cexer
@WXX
你說(shuō)“如果單就消息的派發(fā),那么一個(gè)gui框架可以很容易實(shí)現(xiàn),但是要很好的管理窗口之間的關(guān)系,很好的處理鍵盤加速鍵,鼠標(biāo)等這些交互就麻煩了,考慮消息的過(guò)濾等。”
各有難處,但我覺得后者更容易一點(diǎn),以前我也都做過(guò)一些。我覺得好的框架應(yīng)該是在所有東西之前的。先有骨架,然后再說(shuō)高矮胖瘦。長(zhǎng)得是否高大健壯,陽(yáng)光帥氣,就先看骨架如何了。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 19:08 by cexer
@OwnWaterloo
你說(shuō)“沒有完整的,就是你blog上發(fā)的一些片段……”
我找找看,找到了也給你一分。那些片段隱藏了實(shí)現(xiàn)的,看不出什么有價(jià)值的東西。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 19:43 by OwnWaterloo
我去看了看Imperfect C++。因?yàn)槭怯⑽牡模郧爸豢戳艘徊糠志屯A恕?br>我覺得前面都寫得不錯(cuò),ABI、mangling這些問(wèn)題確實(shí)是很困擾……

但property…… 我覺得這并不算C++的Imperfection。
完全是被其他語(yǔ)言給蒙蔽了。

一門語(yǔ)言就應(yīng)該有一門語(yǔ)言的樣子。
比如用C,如無(wú)絕對(duì)必要,就不應(yīng)該模擬出虛函數(shù)與異常機(jī)制。
書里面提到的7種優(yōu)勢(shì),除了最后一種值得考慮,其他全都不值得稱作優(yōu)勢(shì)。

property,C#中的,或者imperfect cpp 里面看起來(lái)的樣子,無(wú)非就是讓如下語(yǔ)法:
o.p( value ); o.set_p( value );
value = o.p(); value = o.get_p();

變成如下語(yǔ)法:
o.p = value;
value = o.p;

如果C++直接提供property的語(yǔ)法,那當(dāng)然是好事。
但不提供,也不見得編程就進(jìn)行不下去了,也沒有絕對(duì)必要去模擬出這種東西。


書中提到的7個(gè)好處,除了最后1個(gè),其他都不是property帶來(lái)的好處。

1. 讀寫控制
非property一樣可以實(shí)現(xiàn)讀寫控制

2. 內(nèi)外表示轉(zhuǎn)換
這依然是由Date的算法實(shí)現(xiàn),而不是property的功勞。
不通過(guò)property,一樣可以實(shí)現(xiàn)time_t作為內(nèi)部表示,對(duì)外提供int get_xxx()

3. 驗(yàn)證
這個(gè)更搞笑了。
就在書中這句話的下面列出的代碼,就明顯說(shuō)明對(duì)day的驗(yàn)證是通過(guò):
void Date::set_DayOfMonth(int day);
完成的。

完全沒有property的半分功勞。

4. 沒看太明白
書中的意思是, Date.Now是一個(gè)緩存,Date::get_Now()是一個(gè)計(jì)算?
其實(shí),這里真正需要的是"兩種語(yǔ)意",而不是property。
這兩種語(yǔ)意是:
Date::getNow();
Date::updateNow();

書中只是將getNow的語(yǔ)意,用property來(lái)表現(xiàn);get_Now同時(shí)完成updateNow和getNow。


5. 可用性?
We didn't have to write date.get_Month(), just date.Month.
少敲點(diǎn)鍵盤而已……
如果利用重載,用void Month(value)代表set,用value Month(void)代表get,少敲的,就是一個(gè)調(diào)用操作符……

6. 不變式?
沒看太明白。
沒有property,也可以維護(hù)object的不變式,是吧?
只要將數(shù)據(jù)hide,通過(guò)public interface去操作,就可以了。

7. 范型編程
我覺得就只有這個(gè)說(shuō)到點(diǎn)子上了。 而這個(gè)也就是模擬property的真正的作用:改變語(yǔ)法。
template<typename P>
void distance(const P& p1, const P& p2 ) {
假設(shè)這是一個(gè)計(jì)算2個(gè)點(diǎn)歐式距離的函數(shù)。 它已經(jīng)通過(guò):
p1.x;
這種語(yǔ)法,而不是p1.x(); 這種語(yǔ)法寫成了。
}

如果新實(shí)現(xiàn)一個(gè)class, 想通過(guò)p1.x 這種語(yǔ)法訪問(wèn),同時(shí)還要有讀寫控制等, 就需要模擬出property。
這可能是property真正的用處。




換句話說(shuō),真的存在很多情況,使得我們"不得不"使用如下語(yǔ)法:
o.p = value;
value = o.p;

來(lái)代替如下語(yǔ)法:
o.set_p( value );
value = o.get_p();
嗎?

對(duì)這種情況,property模擬才是有價(jià)值的。


對(duì)很多情況,setter/getter的語(yǔ)法和property的語(yǔ)法都是可行的。
如果本身提供了property語(yǔ)法的語(yǔ)言,那使用2者之一都沒關(guān)系。
但C++沒有提供。對(duì)這種情況也非要去模擬出property的語(yǔ)法,就有點(diǎn)…… 為了property而property的味道了。


我繼續(xù)去看書中怎么實(shí)現(xiàn)的……
我以前了解的實(shí)現(xiàn)方式,每一個(gè)proxy至少得帶一個(gè)指針……
這消耗還是蠻嚴(yán)重的……


你怎么看?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 19:57 by OwnWaterloo
我暈……
侵入式的property……

強(qiáng)大……

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 20:13 by cexer
@OwnWaterloo
你說(shuō)“我去看了看Imperfect C++。因?yàn)槭怯⑽牡模郧爸豢戳艘徊糠志屯A恕矣X得前面都寫得不錯(cuò),ABI、mangling這些問(wèn)題確實(shí)是很困擾……我繼續(xù)去看書中怎么實(shí)現(xiàn)的……”
在C++里面屬性只是看起來(lái)很美的東西,其實(shí)用性和想像的有差距。你說(shuō)得對(duì),用方法能實(shí)現(xiàn)所有的功能,所以我的GUI框架已經(jīng)去掉了屬性支持。

你說(shuō)“我以前了解的實(shí)現(xiàn)方式,每一個(gè)proxy至少得帶一個(gè)指針……這消耗還是蠻嚴(yán)重的……”
不一定得帶指針的。比如《C++ Imperfect》里實(shí)現(xiàn)的屬性是不需要帶指針的,但它不被C++標(biāo)準(zhǔn)支持,應(yīng)用有限制。我也實(shí)現(xiàn)了不需要帶指針的屬性,同時(shí)也是跟C++標(biāo)準(zhǔn)相容的,以后會(huì)說(shuō)一下這個(gè)實(shí)現(xiàn)。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 20:31 by OwnWaterloo
@cexer
Imperfect C++中的差不多看明白了……
proxy是包含在object中,通過(guò)proxy在object中的offset得到object的地址……


# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 20:48 by 空明流轉(zhuǎn)
你還是講講2012比較好。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 22:02 by OwnWaterloo
@cexer
我想到一個(gè)幾乎沒有消耗的方案……
我再完善一下……

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 22:07 by cexer
@OwnWaterloo
你說(shuō)“我想到一個(gè)幾乎沒有消耗的方案……我再完善一下……”
加油,出來(lái)了別忘了寫出來(lái)大家分享。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 22:08 by cexer
@空明流轉(zhuǎn)
好的,是這樣的,《2012》說(shuō)的是地球毀滅的故事,好了我說(shuō)完了。
哈哈!

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-15 22:33 by OwnWaterloo
@cexer
關(guān)鍵點(diǎn)在于:"如何通過(guò)proxy地址,得到object地址"。
 
1. 可以給proxy放入一個(gè)object的指針。每個(gè)proxy消耗一個(gè)指針的空間。
太浪費(fèi)了……
 
2. Imperfect C++中利用offset來(lái)計(jì)算object的地址,使得每個(gè)proxy不含任何域。
但C++為了區(qū)別各個(gè)proxy,會(huì)給每個(gè)proxy進(jìn)行填充,依然會(huì)造成消耗。
 
 
3. 避免proxy在Record中被填充
假設(shè)有如下記錄:
Record
{
        proxy1 property1;
        proxy2 property2;
        proxy3 property3;
        ...
}
其中proxy1,proxy2,proxy3, ...  是空結(jié)構(gòu)。
 
Record r;
r.property1;
r.property2;
r.property3;
...
 
在C/C++中,如果想要property1、2、3、... 不占空間,也就是它們必須擁有相同的地址。
也就是說(shuō)…… Record 是union……
 
 
4. 避免Record在class中被填充
即使這樣,整個(gè)union依然是會(huì)被填充……
所以,可以將class的數(shù)據(jù)和union放在一起,就真的不消耗任何空間了……
(如果類本身不需要數(shù)據(jù),那這個(gè)類也是會(huì)被填充的,proxys依然沒有消耗多余的空間)
 
 
代碼:
class date
{
private:
        
struct second_proxy
        {
                
operator int() const
                {
                        
const void* o = this;
                        
int sec = static_cast<const date*>(o)->get_second();
                        printf(
"%d second_proxy::operator int(%p);\n",sec,o);
                        
return sec;
                }
                date
& operator=(int sec)
                {
                        
void* o = this;
                        printf(
"second_proxy::operator=(%p,%d);\n",o,sec);
                        date
* d = static_cast<date*>(o);
                        d
->set_second(sec);
                        
return *d;
                }
        };

public:
        union
        {
                time_t time_;
                second_proxy second;
        };

        date()
        {
                printf(
"date::date(%p);\n",(void*)this);
                time(
&time_);
        }

        
int get_second() const
        {
                
int sec = localtime(&time_)->tm_sec;
                printf(
"%d date::get_second(%p);\n",sec,(void*)this);
                
return sec;
        }

        
void set_second(int sec)
        {
                printf(
"date::set_second(%p,%d);\n",(void*)this,sec);
                tm t 
= *localtime(&time_);
                t.tm_sec 
= sec;
                time_ 
= mktime(&t);
        }
};

second_proxy hour和date的數(shù)據(jù)time_t time_放在同一個(gè)union中。
這樣,它們擁有相同的地址。
在second_proxy::operator int() const; 中,可以直接將this轉(zhuǎn)換到const date* ……
就這樣得到了…… object的地址……
 
 
在C中,必須給那個(gè)union取一個(gè)名字:
struct date
{
        union
        {
                time_t time_;
                second_proxy second;
        } must_have_a_name;
};
struct date date;
date.must_have_a_name.second; 必須這樣訪問(wèn)……
 
C++中有匿名聯(lián)合,所以可以直接:
date d;
d.second;
 
 
這樣的壞處也很明顯……
客戶代碼可以訪問(wèn) d.time_;   什么都完蛋了……
 
 
我再想想怎么隱藏……
 

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 02:48 by OwnWaterloo
關(guān)于隱藏time_成員……
 
1.
class C
{
public:
        union
        {
                proxy1 property1;
                proxy2 property2;
                proxy3 property3;
                // private: // msvc和gcc這里是不能加入private的(具體要查標(biāo)準(zhǔn))
        }
};
 
 
2.
class C
{
public:
        union
        {
                proxy1 property1;
                proxy2 property2;
                proxy3 property3;
        }
private:
        struct impl impl_; // 一旦不放在union中
        // properties就可能會(huì)被填充
};
 
 
仔細(xì)選擇union的位置,可能會(huì)起到減少總大小的效果,比如:
class C1 {
        char c_;
public:
        union { /* properties */ };
private:
        int i_;
};
class C2 {
        int i_;
        char c_;
public:
        union { /* properties */ };
};
 
因?yàn)閏har c_;的附近本來(lái)就會(huì)被填充,properties剛好占據(jù)那個(gè)位置。
 
 
如果這樣,就可能會(huì)很糟糕:
class C3 {
        char c_;
        int i_;
public:
        union { /* properties */ };
};
 
C++標(biāo)準(zhǔn)沒有說(shuō)class的layout應(yīng)該怎么安排。
每個(gè)access secion中的data,必須按聲明順序。
但不同access secion之間,可以打亂順序 —— 這個(gè)也許會(huì)有一些幫助。
 
第2種方案依然需要計(jì)算offsetof…… 這是很不靠譜的……
 
 
3.
作為base。
 
struct properties
{
        union
        {
                proxy1 property1;
                proxy2 property2;
                proxy3 property3;
                // ...
        }
};
 
class C : public properties
{
        // data
};
 
這樣,可以很容易計(jì)算出C的位置:
void property_proxy::operator=( ... ) {
        void* p = this;
        C* c = static_cast<C*>( static_cast<properties*>(p) );
}
 
編譯器會(huì)正確計(jì)算出C*,即使在多繼承下也行。比如:
class C : other , public properties {};
 
但是,在msvc和gcc上,properties 都不會(huì)執(zhí)行空基類優(yōu)化…… 很囧……
仔細(xì)安排data的布局(在這2款編譯器上,將小對(duì)齊的數(shù)據(jù)放前面),也會(huì)影響整個(gè)類的大小。
 
 
2和3的方案,如果能鉆到空子,就可以幾乎沒有代價(jià)的實(shí)現(xiàn)property。
空子就是說(shuō),那個(gè)class本來(lái)就有一些需要被填充的空洞……
 
如果沒有空可鉆……  或者沒有正確安排位置…… 會(huì)多占用一些大小。
額外大小不超過(guò)class中所有域中需要最大對(duì)齊那個(gè)成員的大小。
額外大小和properties的數(shù)量是無(wú)關(guān)的, 多少個(gè)properties都占用這么多額外大小, union嘛……
 
 
4.
還有一種方案。
其實(shí)上面的date,缺陷在于time_t time_; 這個(gè)成員會(huì)被外界訪問(wèn)。
 
可以這樣:
class date {
        class impl {
                time_t time_;
                friend class date;
        };
public:
        union
        {
                impl impl_;
                proxy1 property1;
                proxy2 property2;
                proxy3 property3;
        }
        // ...
};
 
這樣,客戶代碼可以訪問(wèn)的,只有impl_這個(gè)名字。
但是幾乎不能拿它作任何事情。
連它的類型名 —— date::impl —— 都是不可訪問(wèn)的。
 
 
這個(gè)方案的缺陷就是 —— 通常必須從頭設(shè)計(jì)一個(gè)類型。
union中不能放非pod。只能從內(nèi)建類型開始,構(gòu)造一些類。
 
比如已經(jīng)有某個(gè)非pod的類,C,想將C作為一個(gè)成員,實(shí)現(xiàn)Cex:
 
class Cex
{
        union
        {
                C impl_; // 不行
        }
};
 
只能用上面的property base或者property member……
 
 
5.
范化工作 
這個(gè)…… 再說(shuō)吧……
 如果能有更好的布局方案…… 范化工作就白做了……
 

# re: GUI框架:談?wù)効蚣埽瑢憣懘a[未登錄]  回復(fù)  更多評(píng)論   

2009-11-16 09:42 by foxriver
針對(duì)游戲的每幀更新UI,這種消息結(jié)構(gòu)是沒有什么太大價(jià)值,一堆回調(diào)繼承函數(shù)會(huì)迅速膨脹代碼量。

微軟用消息做UI最大的好處,是效率。可是當(dāng)顯卡,CPU如此快速,為什么不尋找另外一種UI解決方式?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 12:45 by 陳梓瀚(vczh)
之前我已經(jīng)做過(guò)一個(gè)發(fā)在我的頁(yè)面上了,其實(shí)最麻煩的事,Windows所要求的標(biāo)準(zhǔn)界面行為API幾乎都沒實(shí)現(xiàn),而且很雜,舉個(gè)例子:

如果有一個(gè)存在Default Button的窗口,你需要:
在沒有其他按鈕獲得焦點(diǎn)的情況下,將Default屬性設(shè)置給那個(gè)按鈕
在有按鈕獲得焦點(diǎn)的情況下,將Default屬性設(shè)置給有焦點(diǎn)的那個(gè)按鈕
按下Enter的時(shí)候,窗口自動(dòng)激活帶Default屬性的按鈕的事件

還有譬如如何消除task bar上面的窗口按鈕等等,或者往菜單加上圖片(API絕對(duì)沒支持,全部都是owner draw上去的!!!),或者shortcut(菜單的Ctrl + C什么的,也是你自己寫上去而不是系統(tǒng)自帶的,而且你負(fù)責(zé)關(guān)聯(lián)他們),或者Tab轉(zhuǎn)移焦點(diǎn)啦(WS_TABSTOP完全沒用,那是給你實(shí)現(xiàn)轉(zhuǎn)移焦點(diǎn)的時(shí)候去獲取控件的屬性然后決定要不要把焦點(diǎn)給它),或者容器被disable之后上面的控件也要跟著顯示成disable一樣啦,還有Vista以下版本你把一個(gè)checkbox放在groupbox里面是黑掉的,微軟證實(shí)了這個(gè)是bug,不過(guò)他只在Vista修了。諸如此類,林林總總,你慢慢處理……

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 12:56 by 陳梓瀚(vczh)
@OwnWaterloo
光有屬性還不夠,一般來(lái)說(shuō)一個(gè)完整的屬性應(yīng)該是:

a=Object.Property;
Object.Property=b;
Object.Property.OnChanging+=functor;
Object.Property.OnChanged+=functor;

//僅本類可用
Object.Property.Self.OnChanging+=functor;
Object.Property.Self.OnChanged+=functor;

當(dāng)一個(gè)Property是int的時(shí)候,你要重載完所有操作符,才能讓Object.Property1 + Object.Property2這樣子的表達(dá)式成立,這一點(diǎn)不知道你想到了沒。

所以為了提供更加好用的Property,你還得實(shí)現(xiàn)一個(gè)Ref<int>,讓Ref<int>同時(shí)兼容int&和&Object.Property,并且Ref<int>提供所有操作符重載。同時(shí),如果Property和Ref<X>是一個(gè)類的話,最好帶上->以便訪問(wèn)成員函數(shù)。

在C++提供property是一件吃力不討好的事情。還是罷了,之前試過(guò),不值得。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 12:59 by 陳梓瀚(vczh)
@foxriver
請(qǐng)使用.NET的WPF,這就是“當(dāng)顯卡,CPU如此快速”的時(shí)候的“另外一種UI解決方式”。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 13:12 by OwnWaterloo
@陳梓瀚(vczh)
我在上面的評(píng)論也說(shuō)了,在C++中沒有絕對(duì)必要,還是不要模擬這個(gè)東西了。
沒有property,生活一樣可以繼續(xù)。


至于 o.p1 + p.p2, &p.p1, 等模擬,并不是重點(diǎn)。
proxy本來(lái)就和被proxy的對(duì)象有所區(qū)別。
視你需要模擬的程度來(lái)決定編程的復(fù)雜度,或者發(fā)現(xiàn)某種特性無(wú)法實(shí)現(xiàn)。

proxy的重點(diǎn)在于如何高效的在proxy中得到被proxy對(duì)象。
實(shí)現(xiàn)了這個(gè)功能點(diǎn),才是其他op=,op T(), op +, ref proxy的前提 —— 這些技術(shù)基本屬于濫大街了 —— 去看vector<bool> —— 所以我對(duì)這些沒什么興趣。

之所以重新開始研究這個(gè)技巧,是因?yàn)镮mperfect C++中提到了一種代價(jià)很低的方案。
我覺得這個(gè)有點(diǎn)意思,所以繼續(xù)深入了一下。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 13:19 by OwnWaterloo
@陳梓瀚(vczh)
還是用代碼說(shuō)話吧……

上面的date的代碼,重點(diǎn)在于這2行:
union { /* ... */ };

哦,還有一行在我的測(cè)試代碼中,并沒有抄出來(lái):
typedef int assume[sizeof(date)==sizeof(time_t)?1:-1];
這2行才是我想表達(dá)的重點(diǎn) —— 沒有額外的空間消耗,實(shí)現(xiàn)property。


寫上面那些代碼,為的是展示上面那個(gè)重點(diǎn),而不是下面這種爛大街的:
operator = (int);
operator int() const;
這些技術(shù)早就被人討論得七七八八了,相當(dāng)無(wú)聊……


這一點(diǎn)不知道你看出來(lái)了沒?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 13:35 by 陳梓瀚(vczh)
@OwnWaterloo
當(dāng)且僅當(dāng)好用,才有繼續(xù)考慮有沒有消耗的必要。一個(gè)高效的、會(huì)制造麻煩的解決方案一般是不被接受的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 13:45 by cexer
@OwnWaterloo
謝謝你分享你的思考,真的很有創(chuàng)意。建議你可以把你的思考寫到你的博客里,讓更多的人看到。

@陳梓瀚(vczh)
高效的,不會(huì)制造麻煩的東西,也是從不高效的,會(huì)制造麻煩的東西進(jìn)化來(lái)的。所以我覺得只要在思考都是有價(jià)值的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 13:50 by OwnWaterloo
@陳梓瀚(vczh)
1.
如果一個(gè)property需要消耗一個(gè)指針的代價(jià),我認(rèn)為實(shí)現(xiàn)得再好用都是不可接受的…… 高得有點(diǎn)離譜。
很容易一個(gè)類的property的消耗比類本身還要高。
[data of instance]
[pointer]
[pointer]
[pointer]
[pointer]
....
而且所有pointer都指向同一個(gè)地方……

而且上面也提到,真正需要模擬出property的,是類似于point、vector、matrix這種類。
p.x比p.x()更自然。
讓這種類附加額外數(shù)據(jù),也是讓人很難接受的。


2.
是否好用,你可以另外開文章討論。
只是你提到的那些使得proxy好用的技術(shù),都提不起我的興趣。
理由很簡(jiǎn)單 —— 這種文章太多,寫出來(lái)都不好意思和人打招呼。

我關(guān)心的僅僅是proxy如何高效得到被proxy對(duì)象 —— 實(shí)現(xiàn)proxy的前提。

我以前見過(guò)的,包括我自己想到的,都是上面one property one pointer的方案。imp cpp中提到的讓我確實(shí)有眼前一亮的感覺。
而 op T(), op= (T), ref T op + 這些技術(shù),只讓我覺得漲眼睛 —— 看太多,早膩歪了。


如果你的重點(diǎn)依然在proxy如何更仿真上,可能很難提起我的興趣。
如果你有興趣思考proxy如何得到被proxy的object上,或者有一些方案,想法,歡迎分享出來(lái)~_~



"當(dāng)且僅當(dāng)好用,才有繼續(xù)考慮有沒有消耗的必要。一個(gè)高效的、會(huì)制造麻煩的解決方案一般是不被接受的。"
這句話絕對(duì)說(shuō)得過(guò)于絕對(duì)了。
如果你用的是C++、而不是C#,效率絕對(duì)不是可以不掛在心上的事情。
為什么你要用C++,而不是用編程更方便,語(yǔ)法糖更多的C#?好好想想吧。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 14:02 by OwnWaterloo
@cexer
我再想想如何做得更范化一些。
減少需要編寫property的人的重復(fù)勞動(dòng)。

但是遇到了困難……

手工寫union base, union member沒什么問(wèn)題。
要將其做成模板…… 會(huì)遇到先有雞還是先有蛋的問(wèn)題……

比如:
proxy< ..., getter , ... >

實(shí)例化一個(gè)property:
proxy< ..., &date::get_second, ... >; 這里需要date的定義?

而date的定義無(wú)論是union base,union member又需要先實(shí)例化proxy< ... &date::get_second, ... >;……
很囧……


手工寫沒問(wèn)題是因?yàn)椋?br>struct second_proxy {
這里僅僅聲明其布局就可以了
};

然后定義date類

然后實(shí)現(xiàn)proxy::op ...
這里才需要引用到date::&getter


我再想想……


# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 14:50 by 俠客西風(fēng)
準(zhǔn)備把你的博客加到我的友情鏈接里,

很喜歡您的風(fēng)格...

呵呵,

是不是好多好多程序員都很像啊,

還是好多本來(lái)就很像的人都選擇了程序員這個(gè)

獨(dú)特的
浪漫的
理性的
(傾向于)創(chuàng)意的
...

職業(yè)啊

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 15:26 by 陳梓瀚(vczh)
@OwnWaterloo
效率不是一個(gè)可以忽略可用性的理由。我們需要的是一個(gè)在效率和外觀上都達(dá)到一定高度的想法,而不是一個(gè)因?yàn)樾识斐陕闊┑南敕ā<词故荂++,我們也要把它變得更方便。而且剛才的那些操作符重載其實(shí)跟你那個(gè)union沒有沖突,這無(wú)論有興趣與否,都是一個(gè)要解決的問(wèn)題。如果別人解決了一個(gè)帶多余指針的好用的屬性,你解決了一個(gè)不帶多余指針的不好用的屬性,那都是沒意義的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 15:28 by 陳梓瀚(vczh)
@OwnWaterloo
不過(guò)用了union,而跟你剛才那樣一個(gè)屬性就要定義一個(gè)類,而不是一種類型的屬性定義一個(gè)類(或者干脆就只有少數(shù)幾個(gè)屬性的類然后到處使用——這個(gè)要求比較高了一點(diǎn)),我覺得比多一個(gè)指針更加不能接受。運(yùn)行時(shí)代價(jià)跟開發(fā)代價(jià)都是需要一并考慮的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 15:29 by 陳梓瀚(vczh)
@OwnWaterloo
在關(guān)心程序的質(zhì)量的同時(shí),也要同時(shí)關(guān)心一下如何將廣大程序猿在C++的水深火熱之中解放出來(lái)。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 15:59 by OwnWaterloo
@陳梓瀚(vczh)
"如果別人解決了一個(gè)帶多余指針的好用的屬性,你解決了一個(gè)不帶多余指針的不好用的屬性,那都是沒意義的。"

我那個(gè)是沒有意義的?
我那個(gè)不可以繼續(xù)實(shí)現(xiàn)你所說(shuō)的那些花哨的用法嗎?(為什么說(shuō)花哨,我下面會(huì)說(shuō)明)

我已經(jīng)說(shuō)過(guò)很多次了,"通過(guò)proxy得到被proxy的對(duì)象"是實(shí)現(xiàn)proxy的前提。
必須先滿足這個(gè)前提才能繼續(xù)實(shí)現(xiàn)proxy的其他技巧。

用union會(huì)影響實(shí)現(xiàn)其他技巧嗎? 依然可以。
難道我要把所有我會(huì)的技巧都展現(xiàn)一下嗎?
我不喜歡這樣[color=red]顯擺[/color]。
或者說(shuō),我也喜歡顯擺;但[b]我不喜歡顯擺[color=red]眾人皆會(huì)[/color]的技巧[/b]。
分享一些別人明顯了解的技術(shù),只會(huì)[b][color=red]漲[/color]別人眼睛[/b]。


我只想展示如何高效實(shí)現(xiàn)proxy所需前提這一技巧,如是而已。



btw:為什么我說(shuō)你那些是花哨的技巧。

首先引入一個(gè)概念:"總線式的設(shè)計(jì)"。

假設(shè)你需要實(shí)現(xiàn)一個(gè)函數(shù)f,f需要一個(gè)字符串輸入(暫不考慮wchar_t)。
如何設(shè)計(jì)這個(gè)輸入?yún)?shù)???

1. f(const char* c_style_string);
2. f(const char* first,ptrdiff_t length);

兩者取其一,可能1用得更多一些。

然后,其他所有的String,都向這個(gè)"總線" —— const char*靠攏。
比如std::basic_string要提供c_str(), CString要提供operator const char*()。

為什么要這么做?
1. 避免API的暴增。 直連線是平方增長(zhǎng),而總線是線性增長(zhǎng)。
2. 有些時(shí)候,必須這樣
對(duì)fopen(const char*)你可以繼續(xù)直連線:
fopen(const std::string& );
fopen(const CString& );

對(duì)一個(gè)類:
class C {
open(const char* );
};

C不是你寫的,你不可能為C加入一個(gè)直連線。
你只能繞彎:
open( C& o, const std::string& );
open( C& o, const CStirng& );


回到你說(shuō)的ref<T>。

假設(shè)有一個(gè)函數(shù):
f(int& );
你可以為它直連線。


假設(shè)有一個(gè)類,依然不是你寫的,它只接受int &
class C
{
f(int & );
}

C2有一個(gè)屬性i。
class C2
{
property int i;
}

你要怎么給你的用戶解釋:
C c;
C2 c2;
c.f( c2.i ); 是行不通的,必須
f( c, c2.i ); ???

你能將所有api的匯合點(diǎn)都直連線嗎? 你做不到。


本來(lái)模擬屬性就是一個(gè)很無(wú)聊的事情了。
你告訴用戶,這就是一個(gè)C#中的 get; set; 就ok了,別想著要其他怎么用。
C#中可以 &o.p嗎???



"運(yùn)行時(shí)代價(jià)跟開發(fā)代價(jià)都是需要一并考慮的。"
你看你是否自相矛盾了。
將線性開發(fā)代價(jià)的總線形式,轉(zhuǎn)化為平方開發(fā)代價(jià)的直連線形式。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:07 by OwnWaterloo
@陳梓瀚(vczh)
"不過(guò)用了union,而跟你剛才那樣一個(gè)屬性就要定義一個(gè)類,而不是一種類型的屬性定義一個(gè)類(或者干脆就只有少數(shù)幾個(gè)屬性的類然后到處使用——這個(gè)要求比較高了一點(diǎn)),我覺得比多一個(gè)指針更加不能接受。運(yùn)行時(shí)代價(jià)跟開發(fā)代價(jià)都是需要一并考慮的。"

先說(shuō)運(yùn)行代價(jià)和開發(fā)代價(jià)。
C程序員可能會(huì)因?yàn)樾剩皇褂胵sort。 他們都是傻子嗎?

"實(shí)現(xiàn)屬性占用的額外空間大小與屬性的數(shù)量無(wú)關(guān)",這難道真的不值得你為其多花點(diǎn)功夫嗎?
這是O(n)到O(1)的優(yōu)化!是不值得的?!


而且我比較懷疑你所說(shuō)的"一種類型的屬性定義一個(gè)類"是一種[color=red]侵入式[/color]的實(shí)現(xiàn)方式。


需要實(shí)現(xiàn)屬性的類本來(lái)就不應(yīng)該很多。
我也想如何做得更范化一些, 但目前成效不大。

就像cexer說(shuō)的"高效的,不會(huì)制造麻煩的東西,也是從不高效的,會(huì)制造麻煩的東西進(jìn)化來(lái)的。"
如果一開始就采用指針保存,那是一輩子就沒辦法優(yōu)化了。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:08 by 陳梓瀚(vczh)
@OwnWaterloo
舉個(gè)簡(jiǎn)單的例子,總線形式的開發(fā)會(huì)讓string有一個(gè)c_str(),而不是讓string消失。我不知道你知不知道解決方案是什么樣子的,但是舉個(gè)例子出來(lái)總是要告訴別人說(shuō),“哦,這個(gè)東西可以這么這么做,只是我懶的寫完整”而不是沒說(shuō)完。

模擬屬性一點(diǎn)都不無(wú)聊,因?yàn)橐粋€(gè)可以監(jiān)聽和撤銷屬性變化的系統(tǒng)非常容易擴(kuò)展,總比你一個(gè)類都來(lái)一個(gè)listener或者就像api一樣所有的消息的格式都很混亂的好。特別對(duì)于開發(fā)GUI的庫(kù)。當(dāng)然這就不僅僅是如何響應(yīng)operator=的問(wèn)題了。允許阻止變化的listener總是有開銷的,所以你無(wú)法杜絕它。這也是我第一次舉例子的時(shí)候就說(shuō)出來(lái)的一個(gè)可以認(rèn)為是“需求”的東西。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:09 by 陳梓瀚(vczh)
@OwnWaterloo
至于說(shuō)“如果一開始就采用指針保存,那是一輩子就沒辦法優(yōu)化了”,這是不對(duì)的。這跟接口無(wú)關(guān),也就是你一個(gè)property的實(shí)現(xiàn)怎么變化,this指針放的地方換掉了,調(diào)用的代碼都是不用改的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:14 by 陳梓瀚(vczh)
@OwnWaterloo
“需要實(shí)現(xiàn)屬性的類本來(lái)就不應(yīng)該很多。”也不是很正確,當(dāng)然這要看情況了。在我看來(lái),每一個(gè)控件都要實(shí)現(xiàn)可監(jiān)聽的屬性,這些屬性用事件暴露出來(lái)。你愿意設(shè)計(jì)完屬性之后從頭設(shè)計(jì)一次事件的命名和參數(shù)什么的好,還是愿意把它們綁定到屬性里面去?這樣的話開發(fā)控件也不需要考慮提供的事件完整不完整的問(wèn)題了。因?yàn)榭丶臓顟B(tài)都在屬性里面,屬性變更就是狀態(tài)變更,也就都有事件了。這樣做的話設(shè)計(jì)出來(lái)的控件就不會(huì)有winapi那個(gè)消息(我們都知道很難清洗化)的影子了,會(huì)有一個(gè)十分漂亮的設(shè)計(jì)出來(lái)。一般winapi封裝出來(lái)的東西都是在PC上跑的,你會(huì)在意一個(gè)textbox占了1k還是1.1k內(nèi)存嗎?在這里多一個(gè)指針少一個(gè)指針根本不是問(wèn)題。

特別是對(duì)于point,那就是個(gè)變量好了,point沒有行為,所以不需要屬性。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:15 by OwnWaterloo
@陳梓瀚(vczh) "在關(guān)心程序的質(zhì)量的同時(shí),也要同時(shí)關(guān)心一下如何將廣大程序猿在C++的水深火熱之中解放出來(lái)" 我展示的,只是"proxy得到object"的技術(shù)。 你可以繼續(xù)展示proxy得到object之后的"解救廣大C++程序員于水深火熱之中"的其他技術(shù)。 但說(shuō)實(shí)話,我不覺得那些技術(shù)真的能救人于水火
真正救人于水火的,不是玩弄高級(jí)技巧,而是設(shè)計(jì)清晰的接口。
還是上面的例子: C c; C2 c2; c.f( c2.i ); 不能這樣做,只會(huì)讓人感到困擾。 如果i不是屬性,而是成員: c.f( c2.i() ); 不行是很容易理解事情 —— 臨時(shí)對(duì)象不能綁定到非const引用上。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:21 by 陳梓瀚(vczh)
@OwnWaterloo
所以這就是Ref<>的意義了嘛,【在你的系統(tǒng)或由其擴(kuò)展的系統(tǒng)里面】讓你的參數(shù)的引用都能接受屬性,同時(shí)也能接受舊的引用。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:27 by OwnWaterloo
"舉個(gè)簡(jiǎn)單的例子,總線形式的開發(fā)會(huì)讓string有一個(gè)c_str(),而不是讓string消失。我不知道你知不知道解決方案是什么樣子的,但是舉個(gè)例子出來(lái)總是要告訴別人說(shuō),“哦,這個(gè)東西可以這么這么做,只是我懶的寫完整”而不是沒說(shuō)完。"

我相信看的人能明白我代碼中的重點(diǎn)在那里。
我不明白的是你為何看不明白,即使在我說(shuō)了之后。

我再說(shuō)一下吧,如果要讓我說(shuō)"這個(gè)property"還可以這樣玩、又可以那樣玩,我會(huì)覺得很掉價(jià)……
一方面因?yàn)槲椰F(xiàn)在本來(lái)就不喜歡過(guò)分玩弄語(yǔ)言特性。
另一方面,這些技術(shù)實(shí)在是說(shuō)得太多……


如果一定要把所有細(xì)節(jié)都展現(xiàn)出來(lái),不知道評(píng)論的字?jǐn)?shù)會(huì)不會(huì)夠。
而且,展現(xiàn)到什么程度才可以停止?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:32 by OwnWaterloo
"模擬屬性一點(diǎn)都不無(wú)聊,因?yàn)橐粋€(gè)可以監(jiān)聽和撤銷屬性變化的系統(tǒng)非常容易擴(kuò)展,總比你一個(gè)類都來(lái)一個(gè)listener或者就像api一樣所有的消息的格式都很混亂的好。特別對(duì)于開發(fā)GUI的庫(kù)。當(dāng)然這就不僅僅是如何響應(yīng)operator=的問(wèn)題了。允許阻止變化的listener總是有開銷的,所以你無(wú)法杜絕它。這也是我第一次舉例子的時(shí)候就說(shuō)出來(lái)的一個(gè)可以認(rèn)為是“需求”的東西。"

模擬屬性就是很無(wú)聊的工作。
你試著回答一個(gè)問(wèn)題:”這里一定需要operator=嗎? 可以使用命名函數(shù)嗎?
如果回答是“是” ,那這里就寧可采用命名函數(shù),而不是屬性。
絕大部分回答都應(yīng)該是“是”。所以這根本不算一個(gè)需求。


從我的直覺上來(lái)說(shuō),模擬屬性使用的價(jià)值并不大。沒有多少場(chǎng)合非屬性不可
如果你可以想到一個(gè)“不是”的例子,請(qǐng)列舉出來(lái)。
也許我的直覺是錯(cuò)的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:32 by OwnWaterloo
"模擬屬性一點(diǎn)都不無(wú)聊,因?yàn)橐粋€(gè)可以監(jiān)聽和撤銷屬性變化的系統(tǒng)非常容易擴(kuò)展,總比你一個(gè)類都來(lái)一個(gè)listener或者就像api一樣所有的消息的格式都很混亂的好。特別對(duì)于開發(fā)GUI的庫(kù)。當(dāng)然這就不僅僅是如何響應(yīng)operator=的問(wèn)題了。允許阻止變化的listener總是有開銷的,所以你無(wú)法杜絕它。這也是我第一次舉例子的時(shí)候就說(shuō)出來(lái)的一個(gè)可以認(rèn)為是“需求”的東西。"

模擬屬性就是很無(wú)聊的工作。
你試著回答一個(gè)問(wèn)題:”這里一定需要operator=嗎? 可以使用命名函數(shù)嗎?
如果回答是“是” ,那這里就寧可采用命名函數(shù),而不是屬性。
絕大部分回答都應(yīng)該是“是”。所以這根本不算一個(gè)需求。


從我的直覺上來(lái)說(shuō),模擬屬性使用的價(jià)值并不大。沒有多少場(chǎng)合非屬性不可
如果你可以想到一個(gè)“不是”的例子,請(qǐng)列舉出來(lái)。
也許我的直覺是錯(cuò)的。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:34 by 矩陣操作
終于能看到一篇提起興趣的文章了。

我也寫過(guò)一個(gè)類似GUI框架,很lite,相當(dāng)lite。主要也是因?yàn)橐嫘枰⌒鸵粋€(gè)窗口系統(tǒng)。
風(fēng)格上也是模擬了NET的方式,實(shí)現(xiàn)了一個(gè)Application::run(&win);這樣的玩意。window的消息映射上沒有去追求用標(biāo)準(zhǔn)CPP,直接用了VC特有的__event,__hook這些東西。
期待博主進(jìn)一步討論!

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:41 by 陳梓瀚(vczh)
@OwnWaterloo
其實(shí)舉過(guò)了嘛,textBox.Text.OnChanging+=a_functor_that_want_to_check_the_input;你覺得在一個(gè)【上百個(gè)】屬性的Form(你不要告訴我一個(gè)窗口的狀態(tài)很少)里面,你打算怎么處理屬性和事件之間的關(guān)系,我一直都在強(qiáng)調(diào)這一點(diǎn),而不是語(yǔ)法上的問(wèn)題,operator=其實(shí)也是個(gè)例子,我沒有強(qiáng)調(diào)說(shuō)要不要有個(gè)名字之類的東西。

另外,不要覺得什么掉價(jià)不掉價(jià)的,技術(shù)沒有貴賤之分,不要搞三六九等。話說(shuō)我自己在搞語(yǔ)言設(shè)計(jì)和實(shí)現(xiàn)。從來(lái)跟這些property什么的關(guān)系不大,這估計(jì)是職業(yè)病。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:42 by OwnWaterloo
"當(dāng)然這要看情況了。在我看來(lái),每一個(gè)控件都要實(shí)現(xiàn)可監(jiān)聽的屬性,這些屬性用事件暴露出來(lái)。你愿意設(shè)計(jì)完屬性之后從頭設(shè)計(jì)一次事件的命名和參數(shù)什么的好,還是愿意把它們綁定到屬性里面去?這樣的話開發(fā)控件也不需要考慮提供的事件完整不完整的問(wèn)題了。因?yàn)榭丶臓顟B(tài)都在屬性里面,屬性變更就是狀態(tài)變更,也就都有事件了。這樣做的話設(shè)計(jì)出來(lái)的控件就不會(huì)有winapi那個(gè)消息(我們都知道很難清洗化)的影子了,會(huì)有一個(gè)十分漂亮的設(shè)計(jì)出來(lái)。"

消除winapi的影子,一定需要屬性嗎?命名函數(shù)不可以嗎?
如果語(yǔ)言本身提供屬性,那使用兩者之一都沒什么問(wèn)題。
如果語(yǔ)言本身不提供,為何在可以使用命名函數(shù)的地方,非要去使用屬性???



"一般winapi封裝出來(lái)的東西都是在PC上跑的,你會(huì)在意一個(gè)textbox占了1k還是1.1k內(nèi)存嗎?在這里多一個(gè)指針少一個(gè)指針根本不是問(wèn)題。 "
在gui上,你的說(shuō)法是正確的。你甚至可以使用boost::any + boost::tuple來(lái)得到一個(gè)類似python的開發(fā)方式。

我討論的是"proxy得到object", 請(qǐng)不要將討論窄化gui上。
作為一個(gè)庫(kù)(非gui庫(kù))的提供者,效率不是最主要的,但無(wú)端的損害(大量損害)就是不可接受的了。
假設(shè)某天你真的需要將proxy應(yīng)用到critical的場(chǎng)景,你就會(huì)后悔當(dāng)初沒有去考慮這個(gè)問(wèn)題了。


"特別是對(duì)于point,那就是個(gè)變量好了,point沒有行為,所以不需要屬性。"
需要的。我舉個(gè)例子:
point
{
        property double x { get;set; }
        property double y { get;set; }
        property double radius { get; set; }
        property double seta { get; set; }
};

客戶可以用直角坐標(biāo)或者極坐標(biāo)去操作這個(gè)點(diǎn)。
點(diǎn)的內(nèi)部表示客戶無(wú)須關(guān)心。
這樣的點(diǎn),就需要行為。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:43 by 陳梓瀚(vczh)
@陳梓瀚(vczh)
至于其他的例子,你可以參考WPF強(qiáng)大的布局功能是怎么【under control】的,用傳統(tǒng)的方法根本沒法讓程序變得清晰。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:45 by 陳梓瀚(vczh)
@OwnWaterloo
【窄化】不是問(wèn)題。GUI是一個(gè)龐大的東西,一旦需要了,那就有做的必要,就算除了GUI以外的所有系統(tǒng)都不能從這個(gè)property機(jī)制上獲得好處,也不是不搞的理由。而且讓一個(gè)例子舉現(xiàn)在一個(gè)范圍里面可以讓我們都少想很多東西。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:46 by 陳梓瀚(vczh)
@OwnWaterloo
行為指的是受改變的時(shí)候發(fā)生的事情,而不是你能從一個(gè)數(shù)據(jù)里面計(jì)算出什么東西。坐標(biāo)轉(zhuǎn)換是映射,點(diǎn)在任何情況下都不可能因?yàn)槟阍O(shè)置了一個(gè)什么坐標(biāo)而做了一些什么事情,因此沒有行為。當(dāng)然cache不同坐標(biāo)系下的結(jié)果例外,這不是重點(diǎn)。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:49 by 陳梓瀚(vczh)
@OwnWaterloo
其實(shí)舉過(guò)了嘛,textBox.Text.OnChanging+=a_functor_that_want_to_check_the_input;你覺得在一個(gè)【上百個(gè)】屬性的Form(你不要告訴我一個(gè)窗口的狀態(tài)很少)里面,你打算怎么處理屬性和事件之間的關(guān)系,我一直都在強(qiáng)調(diào)這一點(diǎn),而不是語(yǔ)法上的問(wèn)題,operator=其實(shí)也是個(gè)例子,我沒有強(qiáng)調(diào)說(shuō)要不要有個(gè)名字之類的東西。

另外,不要覺得什么掉價(jià)不掉價(jià)的,技術(shù)沒有貴賤之分,不要搞三六九等。話說(shuō)我自己在搞語(yǔ)言設(shè)計(jì)和實(shí)現(xiàn)。從來(lái)跟這些property什么的關(guān)系不大,這估計(jì)是職業(yè)病。

【剛才看你在我之后刷了,也不知道看到?jīng)]有,所以再?gòu)?fù)制一次。如果你看過(guò)了就忽略】

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 16:56 by OwnWaterloo
【其實(shí)舉過(guò)了嘛,textBox.Text.OnChanging+=a_functor_that_want_to_check_the_input;你覺得在一個(gè)【上百個(gè)】屬性的Form(你不要告訴我一個(gè)窗口的狀態(tài)很少)里面,你打算怎么處理屬性和事件之間的關(guān)系,我一直都在強(qiáng)調(diào)這一點(diǎn),而不是語(yǔ)法上的問(wèn)題,operator=其實(shí)也是個(gè)例子,我沒有強(qiáng)調(diào)說(shuō)要不要有個(gè)名字之類的東西。 】

textBox.Text.OnChanging+=a_functor_that_want_to_check_the_input;
你覺得改成這樣,可接受不?
textBox.Text.OnChanging.add( a_functor_that_want_to_check_the_input );
textBox.Text.OnChangingSet( a_functor_that_want_to_check_the_input );
textBox.Text.OnChangingAdd( a_functor_that_want_to_check_the_input );

C++就是C++,沒有必要模擬.net那一套。


【另外,不要覺得什么掉價(jià)不掉價(jià)的,技術(shù)沒有貴賤之分,不要搞三六九等。話說(shuō)我自己在搞語(yǔ)言設(shè)計(jì)和實(shí)現(xiàn)。從來(lái)跟這些property什么的關(guān)系不大,這估計(jì)是職業(yè)病。】
因?yàn)槲矣X得通過(guò)union來(lái)達(dá)到property的額外空間與property數(shù)量無(wú)關(guān)這個(gè)技巧可能是新奇的。我沒有在其他地方看到過(guò),也是我自己想出來(lái)的。

而proxy的那些技巧,我已經(jīng)看太多,說(shuō)不定大家都知道,我又何必多次一舉?
而且很多都不是我獨(dú)立想出來(lái)的。
所以我覺得說(shuō)出來(lái)很掉價(jià)……

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:01 by OwnWaterloo
【至于其他的例子,你可以參考WPF強(qiáng)大的布局功能是怎么【under control】的,用傳統(tǒng)的方法根本沒法讓程序變得清晰。】

我不懂wpf。
不通過(guò)屬性,而是命名方法,可以做到讓程序清晰么?

如果只是從:
textBox.Text.OnChanging+=a_functor_that_want_to_check_the_input;

變化到:
textBox.Text.OnChanging.add( a_functor_that_want_to_check_the_input );
textBox.Text.OnChangingSet( a_functor_that_want_to_check_the_input );
textBox.Text.OnChangingAdd( a_functor_that_want_to_check_the_input );

我覺得依然很清晰。
也許前者對(duì)C#轉(zhuǎn)到C++的程序員來(lái)說(shuō),前者會(huì)很親切。
但后者才是大部分C++程序員的每天都在使用形式。

你不需要給你的用戶培訓(xùn)“C++中如何模擬property”這種細(xì)節(jié),他就可以使用你的api。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:01 by cexer
@OwnWaterloo
@陳梓瀚(vczh)
討論了那么多,突然發(fā)現(xiàn)怎么兩位同志的觀點(diǎn)都扭轉(zhuǎn)了?
“C++中實(shí)現(xiàn)屬性”這個(gè)問(wèn)題也是討論過(guò)千百遍的了,而且注定是誰(shuí)都無(wú)法說(shuō)服誰(shuí)的問(wèn)題,因?yàn)樗患兇馐且粋€(gè)技術(shù)問(wèn)題。很大程序上和性格喜歡相關(guān)。就好像實(shí)用主義點(diǎn)的程序員,肯定覺得這樣費(fèi)盡力氣去模仿不值得,但藝術(shù)氣質(zhì)一點(diǎn)的程序員,覺得屬性的語(yǔ)法看起來(lái)很漂亮。然后各自用自己的偏好去說(shuō)服對(duì)方,肯定不能成功。
我個(gè)人的觀點(diǎn)是,有總比沒有好。存在即合理,要不然怎么會(huì)那么多的語(yǔ)言提供語(yǔ)言級(jí)的屬性支持了。C++當(dāng)中比這個(gè)急迫要解決的問(wèn)題還很多,但可以預(yù)見,屬性這東西在未來(lái)的某個(gè)C++標(biāo)準(zhǔn)當(dāng)中一定會(huì)出現(xiàn)的,它確實(shí)有著不可磨滅的價(jià)值。

但你們的討論里各自的觀點(diǎn)都很有道理,里面包含的有技術(shù)含量的思考很多,我看過(guò)也很有收獲。所以請(qǐng)你們?cè)谟押煤椭C的氣氛當(dāng)中繼續(xù)嘗試說(shuō)服對(duì)方吧,無(wú)論是什么樣的討論都是思想的碰撞,也是學(xué)習(xí)的很好的方式。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:03 by cexer
@矩陣操作
謝謝,很高興又認(rèn)識(shí)志同道合的朋友。以后請(qǐng)多指教!

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:06 by OwnWaterloo
【【窄化】不是問(wèn)題。GUI是一個(gè)龐大的東西,一旦需要了,那就有做的必要,就算除了GUI以外的所有系統(tǒng)都不能從這個(gè)property機(jī)制上獲得好處,也不是不搞的理由。而且讓一個(gè)例子舉現(xiàn)在一個(gè)范圍里面可以讓我們都少想很多東西。】

就算這種O(n)到O(1)的優(yōu)化因?yàn)樗珡?fù)雜而永遠(yuǎn)用不上,【也不是不搞的理由】。
我這么說(shuō)對(duì)嗎?

討論如何優(yōu)化就是討論如何優(yōu)化。
沒有必要將這種討論限制到某個(gè)范圍內(nèi),然后說(shuō)在這個(gè)范圍內(nèi)不需要這種優(yōu)化。

你不能預(yù)見所有場(chǎng)合都不需要這種優(yōu)化。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:07 by cexer
@俠客西風(fēng)
呵呵謝謝你能喜歡,其實(shí)我對(duì)技術(shù)的探求不是很深,只是迷戀于一些更簡(jiǎn)單更表面的東西。做技術(shù)的人其實(shí)這樣不是很好。
你就不要準(zhǔn)備了,直接把我加進(jìn)去吧。但我不知道怎么加友情鏈接,在后臺(tái)加過(guò)好像沒成功。
很高興認(rèn)識(shí)你!

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:10 by 陳梓瀚(vczh)
@OwnWaterloo
我并沒有反對(duì)你優(yōu)化,我只是說(shuō)“你覺得在一個(gè)【上百個(gè)】屬性的Form里面,你打算怎么處理屬性和事件之間的關(guān)系”。正好本篇是談GUI,因此舉這么個(gè)例子我覺得挺合適的。那我就這么問(wèn)吧,我以為你是知道我在說(shuō)什么的:在一個(gè)包含請(qǐng)求回調(diào)doing和響應(yīng)回調(diào)one(+=也好,.Add也好)的屬性,怎么避免開銷?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:11 by OwnWaterloo
【行為指的是受改變的時(shí)候發(fā)生的事情,而不是你能從一個(gè)數(shù)據(jù)里面計(jì)算出什么東西。坐標(biāo)轉(zhuǎn)換是映射,點(diǎn)在任何情況下都不可能因?yàn)槟阍O(shè)置了一個(gè)什么坐標(biāo)而做了一些什么事情,因此沒有行為。當(dāng)然cache不同坐標(biāo)系下的結(jié)果例外,這不是重點(diǎn)。】

可能我們對(duì)“行為”這個(gè)詞有不同的理解。 那我們不用這個(gè)詞了。

對(duì)剛才說(shuō)的點(diǎn)的例子。半徑絕對(duì)不能直接讀寫對(duì)吧?
所以必須將實(shí)現(xiàn)隱藏起來(lái)(實(shí)現(xiàn)可能是以直角坐標(biāo)存儲(chǔ)), 通過(guò)setter/getter去操作,以維護(hù)點(diǎn)的不變式 —— 半徑不可能小于0。

我說(shuō)的就是這個(gè)意思。

如果你需要可按極坐標(biāo)操作的點(diǎn),就不能直接暴露數(shù)據(jù),必須使用setter/getter或者property。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:13 by 陳梓瀚(vczh)
@陳梓瀚(vczh)
話說(shuō)回來(lái),其實(shí)我覺得你后面的重點(diǎn)已經(jīng)變成了operator=和operator+=與set_和.Add的關(guān)系了,這個(gè)我不想討論,因?yàn)槲乙灿X得無(wú)所謂,用哪個(gè)都好,只要

1:先做的事情寫在前面,后做的事情寫在后面,要花時(shí)間看清楚。
2:不要造成括號(hào)的嵌套,難以維護(hù)。
舉個(gè)例子,挑選列表里面所有偶數(shù)的數(shù)字然后平方,如果你寫成square(even(a_list))就不滿足1和2。
【注意,上面兩點(diǎn)你看過(guò)就算了,我不討論好跟不好,因?yàn)楦黝}沒關(guān)系】

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:15 by 陳梓瀚(vczh)
@OwnWaterloo
對(duì)于你的點(diǎn)的例子,我傾向于CalculateRadius(your_point)。你不能否認(rèn)人們總是下意識(shí)地認(rèn)為獲取屬性比調(diào)用函數(shù)的效率要高,所以那些真的做了事情,又不改變狀態(tài),又只讀的屬性變成函數(shù)比較好。不過(guò)我還是想跟你討論“在一個(gè)包含請(qǐng)求回調(diào)doing和響應(yīng)回調(diào)one(+=也好,.Add也好)的屬性,怎么避免開銷”而不是在這里要不要用只讀的屬性。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:17 by 陳梓瀚(vczh)
@cexer
我跟OwnWaterloo就借著你的地盤版聊了哈

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:19 by OwnWaterloo
【我并沒有反對(duì)你優(yōu)化,我只是說(shuō)“你覺得在一個(gè)【上百個(gè)】屬性的Form里面,你打算怎么處理屬性和事件之間的關(guān)系”。正好本篇是談GUI,因此舉這么個(gè)例子我覺得挺合適的。那我就這么問(wèn)吧,我以為你是知道我在說(shuō)什么的:在一個(gè)包含請(qǐng)求回調(diào)doing和響應(yīng)回調(diào)one(+=也好,.Add也好)的屬性,怎么避免開銷?】

首先,上百個(gè)屬性是否可以改為上百個(gè)×2的getter和setter?
setter不一定難用,setter還可以鏈?zhǔn)奖磉_(dá)呢。

對(duì)比:
1. w.p1(v1).p2(v2).p3(v3) ...
2. ( (w.p1 = v1).p2 = v2 ).p3 = v3 ...
3.
w.p1 = v1;
w.p2 = v2;
w.p3 = v3;


其次,如果真要模擬property。
我真的沒看明白你說(shuō)的那個(gè)需求是什么…… 囧


# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:23 by OwnWaterloo
【我跟OwnWaterloo就借著你的地盤版聊了哈】

要不我們開一個(gè)論壇吧?google groups或者群?
群的聊天資料可能不容易搜出來(lái)……

toplangauge越來(lái)越水了……

把cppblog上的人都招集起來(lái)?

很高興和你們討論問(wèn)題~_~
如果我語(yǔ)氣有過(guò)激之處,請(qǐng)不吝指出,或者多多包涵一下。

有人響應(yīng)沒……?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:26 by 陳梓瀚(vczh)
@OwnWaterloo
我覺得這里挺好的,其他地方都會(huì)水- -b就是cppblog還沒那么多亂七八糟的帖子。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:28 by 陳梓瀚(vczh)
@OwnWaterloo
屬性變化就是狀態(tài)變化嘛,你要監(jiān)聽一個(gè)狀態(tài)的變化,還要控制一個(gè)狀態(tài)變化的權(quán)限,用屬性+事件的組合是很常見的。也就是說(shuō),一個(gè)屬性都要自動(dòng)提供Changing和Changed兩個(gè)事件。嘗試把它做得高效,就是我之前的需求了。

這才是屬性的本質(zhì)概念,跟語(yǔ)法什么的關(guān)系并不大。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:35 by cexer
@陳梓瀚(vczh)
你說(shuō)“我跟OwnWaterloo就借著你的地盤版聊了哈”

絕沒問(wèn)題,歡迎有自己思考的同志來(lái)此版聊,如果能切緊GUI框架的主題就感謝了哈,你們的討論能使我的博文增色不少。聊完不要走,此處管飯。

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:43 by 溪流
哈,關(guān)注~

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:43 by OwnWaterloo
1:先做的事情寫在前面,后做的事情寫在后面,要花時(shí)間看清楚。 
2:不要造成括號(hào)的嵌套,難以維護(hù)。 
舉個(gè)例子,挑選列表里面所有偶數(shù)的數(shù)字然后平方,如果你寫成square(even(a_list))就不滿足1和2。 
【注意,上面兩點(diǎn)你看過(guò)就算了,我不討論好跟不好,因?yàn)楦黝}沒關(guān)系】

不能算了……
text.onchange_set( handler1 ).onchange_add( handler2 ).onchange_add( handler3 );
滿足上面的2點(diǎn)嗎?


對(duì)于你的點(diǎn)的例子,我傾向于CalculateRadius(your_point)。你不能否認(rèn)人們總是下意識(shí)地認(rèn)為獲取屬性比調(diào)用函數(shù)的效率要高,所以那些真的做了事情,又不改變狀態(tài),又只讀的屬性變成函數(shù)比較好。
點(diǎn)的例子是因?yàn)槟阏f(shuō)point不需要行為而舉出的反例。

我也傾向于:
point
{
        double x() const;
        void x(double xx);
        double r() const;
        void r(double rr);
        // ..
};

我也沒有假設(shè)get_r( p ); 和 p.r() 或者p.r到底何種效率更高。
這取決與內(nèi)部表達(dá)是直角坐標(biāo)還是極坐標(biāo)。

這些都不是重點(diǎn)。重點(diǎn)在于:
1. r絕對(duì)不可以是裸域 —— 它需要維護(hù)不變式
2. 如果你打算將x、y、r、a由函數(shù)變?yōu)閷傩裕?個(gè)指針的開銷你覺得是否合適?

btw:這4個(gè)屬性都可以是讀寫的,并不存在x、y讀寫,r、a只讀一說(shuō)。


不過(guò)我還是想跟你討論“在一個(gè)包含請(qǐng)求回調(diào)doing和響應(yīng)回調(diào)one(+=也好,.Add也好)的屬性,怎么避免開銷”而不是在這里要不要用只讀的屬性。
我沒看明白,能否再詳細(xì)一點(diǎn)?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:46 by cexer
@OwnWaterloo
他少打一個(gè)字母!done

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 17:57 by OwnWaterloo
@cexer
絕沒問(wèn)題,歡迎有自己思考的同志來(lái)此版聊,如果能切緊GUI框架的主題就感謝了哈,你們的討論能使我的博文增色不少。聊完不要走,此處管飯。

別管飯了……  正好有一個(gè)懸了很久的關(guān)于ATL/WTL的疑問(wèn),你管管吧~_~

是這樣的,ATL/WTL中提到一種atl-style繼承。
template<typename D>
class B
{
        void f1() { static_cast<D*>(this)->f1_do(); }
        void f2() { static_cast<D*>(this)->f2_do(); }
        void f1_do() { printf("B\n"); }
        void f2_do() { printf("B\n"); }
        
};

class D : public B<D>
{
        void f1_do() { printf("D\n"); }
};

D d;
d.f1();
D::f1不存在 -> 調(diào)用B::f1 -> 轉(zhuǎn)型為D* -> D覆蓋了f1_do -> 調(diào)用D::f1_do ->輸出"D"
d.f2();
D::f2不存在 -> 調(diào)用B::f1 -> 轉(zhuǎn)型為D* -> D::f2_do不存在 -> 調(diào)用B::f1_do->輸出"B"

是這樣嗎?


然后,問(wèn)題就來(lái)了 …… 這個(gè)樣子,除了將代碼寫得更復(fù)雜以外,相比下面的寫法,有什么區(qū)別么??

class B
{
        void f1() { printf("B\n"); }
        void f2() { printf("B\n"); }
};

class D : public B
{
        void f1() { printf("D\n"); }
};

D d;
d.f1(); "D"
d.f2(); "B"


# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 18:02 by OwnWaterloo
@cexer
ATL-style繼承,提供的語(yǔ)意是:
基類提供默認(rèn)實(shí)現(xiàn),派生類繼并覆蓋自己需要的函數(shù)。
是這樣嗎?
除了這個(gè),還有其他功能嗎?

但這個(gè)功能,不正好就是非ATL-style繼承 —— 普通繼承提供的語(yǔ)意嗎……
為什么要繞這么大一個(gè)圈子?
能得到什么好處? header-only?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 18:06 by OwnWaterloo
@陳梓瀚(vczh)
屬性變化就是狀態(tài)變化嘛,你要監(jiān)聽一個(gè)狀態(tài)的變化,還要控制一個(gè)狀態(tài)變化的權(quán)限,用屬性+事件的組合是很常見的。也就是說(shuō),一個(gè)屬性都要自動(dòng)提供Changing和Changed兩個(gè)事件。嘗試把它做得高效,就是我之前的需求了。 

這才是屬性的本質(zhì)概念,跟語(yǔ)法什么的關(guān)系并不大。

我覺得你又開始繼續(xù)扯遠(yuǎn)了……
本來(lái)不是在討論“proxy的實(shí)現(xiàn)技術(shù)”“property和命名函數(shù)”么……

anyway,換個(gè)話題也好。
不過(guò)我真沒看明白你的需求是怎樣的……

這個(gè)需求是否高效,與“是否使用union”有關(guān)系嗎?
與“property vs 命名函數(shù)”有關(guān)系嗎?
是一個(gè)新話題吧?


能詳細(xì)說(shuō)說(shuō)你的需求么?

# re: GUI框架:談?wù)効蚣埽瑢憣懘a  回復(fù)  更多評(píng)論   

2009-11-16 18:08 by cexer
@OwnWaterloo
我的理解是所謂的ATL-Style,其實(shí)是用模板在編譯期手工模擬的一種多態(tài),ATL 的實(shí)現(xiàn)當(dāng)中大量地使用了這種方式,目的就是為了輕量級(jí),幾乎沒用過(guò)虛函數(shù)。
我覺得這種手法的作用不僅僅限于此,因?yàn)榭梢越Y(jié)合其它的編譯期技術(shù),實(shí)現(xiàn)很多虛函數(shù)難以達(dá)到的功能,我實(shí)現(xiàn) GUI 框架的時(shí)候也用到很多這種東西,以后的說(shuō)明中應(yīng)該會(huì)遇到。

評(píng)論共2頁(yè): 1 2 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美伊人久久| 国产日产欧产精品推荐色 | 久久影音先锋| 亚洲电影免费在线| 亚洲一区二区免费视频| 蜜桃精品久久久久久久免费影院| 亚洲视频精品| 欧美日韩一区二区在线| 一区二区三区福利| 亚洲国产欧美久久| 久久综合九色综合欧美狠狠| 欧美日韩另类丝袜其他| 亚洲一区不卡| 亚洲日本激情| 国产精品综合色区在线观看| 伊人久久亚洲美女图片| 久久久久国产精品一区| 久久久免费精品视频| 国产一区二区三区在线观看免费 | 欧美大秀在线观看| 一本色道久久综合一区 | 性欧美大战久久久久久久久| 亚洲人成在线播放网站岛国| 国产欧美短视频| 免费一级欧美片在线观看| 欧美精品一区二区三区蜜臀| 亚洲激情一区二区| 欧美一区二区三区视频免费| 激情欧美一区二区| 国产精品99久久久久久人| 韩国一区二区三区在线观看| 亚洲免费电影在线观看| 亚洲一级在线观看| 亚洲欧洲精品一区二区三区不卡 | 亚洲视频在线播放| 一本色道综合亚洲| 欧美电影电视剧在线观看| 久久xxxx精品视频| 亚洲午夜视频在线观看| 99在线观看免费视频精品观看| 久久精品1区| 欧美不卡视频一区| 亚洲第一久久影院| 极品日韩av| 久久激情一区| 欧美激情亚洲国产| 亚洲第一精品福利| 亚洲激情成人在线| 欧美精品午夜视频| 亚洲一区欧美| 欧美高清视频免费观看| 狠狠色综合日日| 女主播福利一区| 夜夜爽www精品| 午夜宅男久久久| 黄色在线一区| 欧美日韩国产综合网| 欧美日韩精品免费观看视频| 欧美a级一区二区| 日韩午夜免费| 国产精品一区二区久久国产| 久久精品国产成人| 亚洲免费播放| 亚洲午夜久久久久久久久电影院| 国产精品不卡在线| 久久久久青草大香线综合精品| 国产精品一卡二卡| 欧美刺激午夜性久久久久久久| 99国产精品视频免费观看一公开| 香港久久久电影| 亚洲国产电影| 国产日韩欧美中文在线播放| 免费高清在线一区| 亚洲欧美日韩久久精品| 欧美+亚洲+精品+三区| 小黄鸭视频精品导航| av成人免费在线| 亚洲高清一区二| 黄色精品一二区| 国产三级欧美三级| 国产欧美一区二区白浆黑人| 免费在线日韩av| 久久久五月婷婷| 免费人成精品欧美精品| 久久久欧美精品| 美女黄色成人网| 亚洲欧美影院| 亚洲一区激情| 亚洲欧美一区二区三区久久| 亚洲伦伦在线| 亚洲欧美另类在线观看| 亚洲欧美精品在线| 欧美一区二区啪啪| 久久久蜜臀国产一区二区| 久久久亚洲欧洲日产国码αv| 久久国产精品黑丝| 久久综合色播五月| 欧美精品成人一区二区在线观看| 欧美日韩免费观看一区二区三区| 欧美日韩亚洲综合| 激情欧美丁香| 一区二区三区四区五区视频| 午夜精品久久久| 欧美亚洲一级| 亚洲国产视频一区二区| 亚洲精品一级| 亚洲综合色自拍一区| 老牛国产精品一区的观看方式| 欧美国产日韩亚洲一区| 亚洲网站视频| 蜜桃av综合| 韩日午夜在线资源一区二区| 一本色道久久综合亚洲精品高清 | 国产一区二区三区免费在线观看| 亚洲福利国产精品| 欧美有码在线观看视频| 亚洲国产一区二区三区高清| 在线亚洲欧美| 国产精品久久久亚洲一区| 亚洲激情一区二区三区| 欧美久久在线| 欧美日韩在线视频一区| 亚洲制服av| 午夜国产一区| 国产精品乱码妇女bbbb| 亚洲午夜免费视频| 99精品欧美一区| 久久亚洲不卡| 亚洲最快最全在线视频| 99精品国产高清一区二区| 久久青青草原一区二区| 欧美~级网站不卡| 国产精品久久久久久久久久尿| 亚洲第一在线视频| 久久er99精品| 亚洲精品小视频| 亚洲国产黄色片| 亚洲在线国产日韩欧美| 久久国产一区二区| 在线亚洲美日韩| 国产精品久久久久久久久久尿| 亚洲小少妇裸体bbw| 亚洲国产成人高清精品| 欧美/亚洲一区| 欧美日韩久久| 久久蜜桃香蕉精品一区二区三区| 久久亚洲精品欧美| 亚洲专区一区二区三区| 亚洲欧美中文日韩在线| 一区二区视频免费完整版观看| 91久久午夜| 欧美日韩在线播| 亚洲精华国产欧美| 国产日本欧美在线观看| 亚洲国产精品毛片| 国产精品美女午夜av| 亚洲国产高清视频| 国产一区二区三区免费不卡| 日韩视频永久免费| 亚洲精美视频| 久久婷婷色综合| 欧美一区二区三区日韩视频| 欧美激情在线有限公司| 久久精品一区二区三区不卡| 欧美日韩视频在线观看一区二区三区 | 午夜精品久久久久久久男人的天堂 | 亚洲视频在线观看三级| 欧美本精品男人aⅴ天堂| 欧美中文字幕在线观看| 国产精品久久久久av免费| 欧美一区二区三区男人的天堂| 欧美伦理一区二区| 99国产精品久久久久久久久久| 日韩视频在线免费观看| 欧美日韩国产综合视频在线观看中文 | 久久久噜噜噜| 久久乐国产精品| 亚洲国产综合在线| 欧美裸体一区二区三区| 日韩一级大片| 先锋影音久久久| 国产一区二区三区免费观看| 欧美在线一级视频| 亚洲成在人线av| 中国亚洲黄色| 国产又爽又黄的激情精品视频| 久久资源av| 亚洲尤物视频网| 免费不卡欧美自拍视频| 亚洲特级毛片| 欧美一区二区视频97| 欧美在线视频在线播放完整版免费观看 | 免费日韩av电影| 亚洲影院免费| 亚洲片区在线| 久久动漫亚洲| 亚洲欧美日韩另类精品一区二区三区 | 久久精品国产久精国产爱| 亚洲日本一区二区三区| 欧美中文在线视频|