• <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>

            huaxiazhihuo

             

            消息發(fā)送雜談

                  最近在看MFC的代碼,雖然這破玩意,老朽已經(jīng)很熟悉了得不能再熟悉了,但是這些破代碼自由其獨有的吸引力,不說別的,單單理解起來就非常容易,比之什么boost代碼容易看多了,單步調(diào)試什么的,都非常方便,堆棧上一查看,層次調(diào)用一目了然。一次又一次地虐這些曾經(jīng)虐過老朽的代碼,也是人生快事一件。平心而論,mfc的代碼還是寫得挺不錯的,中規(guī)中矩,再加上過去九十年代之初,16位的windows系統(tǒng),那個時候的面向?qū)ο蟮腸++的風(fēng)靡一時,完全采用標(biāo)準(zhǔn)c++,能做成這樣,實屬難能可貴,也在情理之內(nèi)。并且,后面壓上com之后,mfc也不崩盤,采用內(nèi)嵌類實現(xiàn)的com的方式,也很有意思。然后,從mfc中也能學(xué)到不少windows gui的使用方式還有各種其他雜七雜八東西,雖然win32已經(jīng)沒落。但是里面的技術(shù)還是挺吸引人,可以消遣也不錯。當(dāng)然,對于新人,mfc不建議再碰了,mfc真是沒飯吃的意思。你想想,一個gui框架,沒有template可用的情況下,而逆天c++11的lambda作為匿名functor,更加不必提了,只有虛函數(shù)和繼承可用,也沒有exception,能搞成mfc這副摸樣,的而且確是精品。其實,后來的巨硬也有救贖,看看人家用template做出來的專為com打造的atl又是什么樣子呢,然后建構(gòu)在atl的windows thunk基礎(chǔ)上開發(fā)的wtl又是怎樣的小巧玲瓏。巨硬在template上的使用還是很厲害的,atl將template和多繼承用的真是漂亮。人家?guī)资昵熬蛯emplate和多繼承用得如此出神入化,反觀國內(nèi),一大批C with class又或者狗粉一再叫囂template滾出c++,多繼承太復(fù)雜了,運算符重載不透明,心智負擔(dān),隱式類型轉(zhuǎn)換問題太多,virtual是罪惡之源萬惡之首,構(gòu)造函數(shù)析構(gòu)函數(shù)背著馬猿做了太多事情,exception對代碼沖擊太大,打斷代碼正常流行,時時刻刻都好像隱藏著不定時炸彈。依本座看來,C++中一大批能夠顯著減少重復(fù)代碼,帶來類型安全的拔高抽象層次的好東西,對于這些C語言衛(wèi)道士而言,都是混亂之物。其實,c語言就是一塊廢柴,抽象層次太低,可以做文章的地方太少了。
                  就以構(gòu)造函數(shù)和類型轉(zhuǎn)換operator為例,來看看怎么用于C的char *itoa(int value,  char *str,  int radix)。
                  itoa的參數(shù)之所以還需要str入?yún)ⅲ鞘且驗镃語言中缺乏返回數(shù)組的語言元素,所以調(diào)用者要提供一個字符數(shù)組作為緩沖用于存放結(jié)果,但是這個多出來str參數(shù)真是沒必要啊,因為語言能力的欠缺,所以只好把這個負擔(dān)壓到猿猴身上。也有些itoa的實現(xiàn)沒有這個累贅str的入?yún)ⅲ莾?nèi)部static的字符數(shù)組,用于存放結(jié)果并返回給上層。這個版本就只有兩個入?yún)⒘耍且蔡话踩耍瑒e提多線程了。假如,有一個函數(shù)fn(char* str1, char* str2),然后,這樣調(diào)用fn(itoa(num1),itoa(num2)),畫面太美了。另外,那個有多余str參數(shù)版本的itoa也好不到哪里去,要勞心費神準(zhǔn)備兩塊字符數(shù)組,然后還要保證參數(shù)傳遞的時候不要一樣。反正C語言的粉絲整天很喜歡寫這些重復(fù)代碼,并且美其名曰掌控一切細節(jié)的快感。
            請看構(gòu)造函數(shù)和類型轉(zhuǎn)換operator怎么解決。太easy了。

            struct ToString
            {
                
            char text[28];
                
            int length;

                ToString(
            int n)
                {
                    
            //轉(zhuǎn)換字符串,結(jié)果存放于text中
                }

                
            operator const char*()
                {
                    
            return text;
                }
            };
                  并且,這里的ToString還可以安全的用之于printf里面呢,因為它本身就是字符串的化身。為什么是ToString,因為它不僅僅要它ToString int,還有double,bool,char,……
                  不好意思,扯遠了,只是想說,框架或者函數(shù)庫的表現(xiàn)能力也要取決于語言本身的表達能力。就好像C#就可以做出linq那樣爽快的框架,java再怎么拼命也搗鼓不出來一個一半好用的linq,C++也不行,但是C++可以搗鼓類似于haskell中的map,filter,fold等,  并結(jié)合linq的后綴表達方式。就好比下面這樣
                  vector<int> nums = {...}
                  Range(nums).Map(_1 * _1).Filter(_1 % 2).CopyTo(dest); // 用了boost中的lambda表達法,因為的確很簡潔,沒法控制。對于復(fù)雜情況,當(dāng)然要用C++11原生的lambda
                  勉勉強強差可滿足吧。如果C++的lambda參數(shù)可以自動推導(dǎo)就好了,不過也沒什么,主要是ide下用得爽。用泛型lambda也能將就。
                  所以,回過頭來,再看看mfc(沒飯吃),就可以了解其各種隱痛了。真的,以90年代的眼光來看,mfc真是做到極致了。mfc不可能走win32下窗口函數(shù)C語言那樣的消息發(fā)送消息反應(yīng)的正路(邪路)吧。窗口函數(shù)這一套,在90年代面向?qū)ο笫⑿械臅r代,絕對不能被忍受,只是到了前幾年,才被發(fā)現(xiàn)其價值原來不菲,這是解耦合砍繼承樹的好手法,老朽在前幾年也跟風(fēng)吹捧窗口函數(shù)的那一套。平心而論,smalltalk的這一套消息發(fā)送的動態(tài)語言,確實是很強有力的抽象手段,我不管目標(biāo)對象能否反應(yīng)該消息,閉著眼睛就可以給你發(fā)送消息,你能反應(yīng)就反應(yīng),不能反應(yīng)就拉倒,或者調(diào)用缺省的反應(yīng)方式,就好像DefWindowProc(職責(zé)鏈模式?),又或者是拋出異常,怎么做都可以。一下子就解開了調(diào)用者和目標(biāo)對象的類型耦合關(guān)系。面向?qū)ο笾校l(fā)送和消息反應(yīng)才是核心,什么封裝繼承多態(tài),那是另一套抽象方式,雖然坊間說這也是面向?qū)ο蟮幕疽兀遣皇牵?dāng)然,這或許也只是個人觀點。
                  或許,從某種意義上講,C++/java/C#一類的成員函數(shù)調(diào)用形式,其實也算消息發(fā)送吧。比如,str.length(),就是給對象str發(fā)送length的消息,然后str收到length消息,作出反應(yīng),執(zhí)行操作,返回里面字符串的長度。靠,這明明就是直接的函數(shù)調(diào)用,搞什么消息發(fā)送的說辭來強辯,顛倒是非黑白,指鹿為馬。可不是嗎?編譯器知道str是字符串類型,知道length成員函數(shù),馬上就生成了高效的函數(shù)調(diào)用方式。在這里,沒有任何動態(tài)多態(tài)的可能,發(fā)生就發(fā)生了,一經(jīng)調(diào)用,動作立馬就行動,沒有任何商量的余地。耦合,這里出現(xiàn)強耦合,調(diào)用者和str綁在一塊了,假如以后出現(xiàn)更高效率更有彈性的string的代替品了,可是沒法用在這里了,因為這里str.length()的綁定很緊很緊。
                  人家消息發(fā)送就不一樣了,動態(tài)的,可以動態(tài)替換對象,替換方法,彈性足足。并且,消息發(fā)送的模式下,對象收到消息,要判斷消息,解析消息,找到消息的執(zhí)行函數(shù),最后才終于執(zhí)行任務(wù)。這么多間接層,每一層都可以做很多很多文章。比如,在消息到達對象之前做文章,就可以搞消息隊列,把消息和參數(shù)暫存起來,這個時候,什么actor模式就大放異彩,至于undo,redo,更加是小菜一碟。然后呢,再給對象安裝消息解析器,把消息和消息參數(shù)轉(zhuǎn)換成其他類型消息。比如原本對象不能反應(yīng)這條消息,但是對消息參數(shù)稍加修飾,然后在發(fā)送給對象,這不就是適配器模式。總之,可操作可挖掘的空間太大了,遠遠不止23條。
                  但是,封裝繼承多態(tài)就一無是處了嗎?不是的,最起碼一點,編譯期間可以報錯。因為的確有很多時候,我們明明就知道對象的類型,明明就知道對象不可能是其他類型,比如字符串,比如復(fù)數(shù),比如數(shù)組這些玩意,無論如何,它們都不需要動態(tài)消息的能力。我們就知道手上的對象就是字符串就是復(fù)數(shù),不可能是別的,并且,我們就是要明確地調(diào)用length函數(shù)。我們就是要編譯器幫忙檢查這里潛在的語法類型錯誤,比如對復(fù)數(shù)對象調(diào)用length函數(shù),編譯器馬上就不高興了。并且,一切都是確定的,所以編譯器也能生成高效的代碼,高效的不能再高效了。對此,消息發(fā)送的面向?qū)ο缶妥霾坏搅耍还苁鞘裁磳ο螅琲nt,string,complex種種,都來個消息發(fā)送。這樣一來,靜態(tài)類型檢查和高效的代碼,就木有了。
            考察一下,面向?qū)ο笥械燃壷郑徊揭徊剑羞M化的階梯。每進化一次,就多了一層間接,類型耦合就降低,就進一步超越編譯器的限制,當(dāng)然,也意味著編譯器幫忙檢查類型錯誤生成高效代碼就弱了一分。事情往往就是,有所得必有所失。少即是多,多即是少。因此,可推得少即是少,多即是多。少始終是少,多始終是多。
                  一切,還是要從C語言說起,C語言中,沒有class,沒有函數(shù)重載。函數(shù)名是什么,最后就是什么。在這種條件下,代碼多了,每個新的函數(shù)名字要考究半天,一不小心,要么函數(shù)名字就會很長,要么函數(shù)名字短了要沖突或者不好理解。但是好處是,最后生成目標(biāo)代碼時,什么函數(shù)名字就是什么名字,所見即所得,沒有異常,不會搗鬼,于是其他各種語言都可以高高興興開開心心調(diào)用。猿猴觀碼,也很清晰。C++也是在這里賺了第一桶金。其實,這么苛刻的條件下,最考究猿猴的代碼架構(gòu)能力,架構(gòu)稍微不好,最后都勢必提早崩掉,前期就可以過濾很多垃圾架構(gòu)。
                  然后就是C with class了,開始在函數(shù)名字上面做文章了。同一個函數(shù)名字依對象類型,開始擁有靜態(tài)多態(tài)能力了。比如,str.length(),這是對字符串求長度。數(shù)組的變量,nums.length(),對數(shù)組求長度。同一個length的名字,用在不同的對象上,就有不同的意義。這如何做到呢,最初,cfront(第一版C++編譯器)的處理方式是,可以說是語法糖,就是在名字和調(diào)用形式上做文章,比如,str.length(),變成,string_length(&str),array_length(&nums)。別小看這點小把戲語法糖,這真是有力的抽象手法。不說別的,就說起名字吧,可以統(tǒng)一length了,無須費思量string_length,list_length了。然后,對象統(tǒng)一調(diào)用方式,str.length(),list.length(),函數(shù)確定這種吃力不討好的事情就交給編譯器去做好啦,解放部分腦細胞。這,的確很好,但是,全局函數(shù)是開放式的,而對象的成員函數(shù)是封閉的,一旦class定義完畢,成員函數(shù)的數(shù)量也就定死了。猿猴最講究東西的可擴展性,不管成員函數(shù)多么方便多么抽象有力,就擴展性而言,就差了一大截,其他優(yōu)勢都彌補不了。語義上看,擴展成員函數(shù)的語法完全與原生的一樣,增加一個簡單的語法形式來擴充,但是多年下來,標(biāo)準(zhǔn)委員會都不務(wù)正業(yè),哎。顯然,編譯器的類型檢查能力和生成的代碼性能,沒有任何減少,但是,猿猴看代碼,不能再所見所得了,必須根據(jù)對象類型,才能確定最終的目標(biāo)函數(shù)。就這么點小改進,當(dāng)時C++馬上就展示其驚人的吸引力。假如,C++只能留在這一層,相信到今天為止,可以吸引到更多的c粉。可是,C++開始叛變。
                  C++的函數(shù)重載,還有操作符重載,外加隱式類型轉(zhuǎn)換和隱式構(gòu)造函數(shù),還有const,volatile修飾,當(dāng)然,代碼可以寫得更加簡潔,編譯器可以做的事情也更多啦,但是函數(shù)的調(diào)用再也不明確了。部分專注于底層的猿猴的弱小的抽象能力把控不住了,不少人在這里玩不動了。此外,命名修飾把最終函數(shù)名字搞得亂七八糟,二進制的通用性也要開始廢了。導(dǎo)致C++的dll不能像C那樣到處通吃。像是狗語言就禁止函數(shù)重載這個功能。大家好像很非難C++的操作符重載,但是haskell還能自定義新的操作符呢。雖然在這里,編譯器還能生成高效代碼,但是,各種奇奇怪怪類型轉(zhuǎn)換的規(guī)則,編譯器也偶爾表現(xiàn)出奇,甚至匪夷所思,雖然一切都在情理之內(nèi)。
                  其實,不考慮什么動態(tài)能力,單單是這里的靜多態(tài),基于對象(俗稱ADT)的抽象模式,就可以應(yīng)付70%以上的代碼了。想想以前沒有靜多態(tài)的C日子是怎么過的。
                  此時,開始兵分兩路,C++一方面是動多態(tài)發(fā)展,表現(xiàn)為繼承,多繼承,虛繼承,虛函數(shù),純虛函數(shù),rtti(廢物,半殘品),到此為止了,止步不前;另一方面是繼續(xù)加強靜多態(tài),王者,template,一直在加強,模板偏特化,template template,varidiac tempalte,consexpr, auto,concept,……,背負著各種指責(zé)在前進,就是在前進。C++企圖以靜態(tài)能力的強悍變態(tài)恐怖,不惜榨干靜態(tài)上的一點點可為空間,累死編譯器,罔顧邊際效應(yīng)的越來越少,企圖彌補其動態(tài)上的種種不足。這也是可行的,畢竟haskell都可以做到。template的話題太龐大了,我們言歸正傳,面向?qū)ο蟆?br />      下面就是被指責(zé)得太多的C++多繼承,虛函數(shù),RTTI,脆弱的虛函數(shù)表,等,這些說法,也都很有道理,確是實情,兼之C++沒有反射,沒有垃圾回收,用上面這些破玩意搗鼓,硬著頭皮做設(shè)計做框架,本來就先天能力嚴重不足,還要考慮內(nèi)存管理這個大敵(循環(huán)引用可不是吹的),更有exception在旁虎視眈眈,隨時給予致命一擊。更要命的是,多繼承,虛函數(shù),虛繼承,這些本來就殺敵八百自傷一千,嚴重擾亂class的內(nèi)存布局,你知道vector里面隨隨便便插入元素,對于非pod的元素,不僅僅是移動內(nèi)存,騰出新位置來給新對象安營扎寨,還要一次又一次地對被移動的對象執(zhí)行析構(gòu)拷貝構(gòu)造。沒有這些奇奇怪怪的內(nèi)存布局,vector的實現(xiàn)應(yīng)該會清爽很多。稍微想想,這實在太考究猿猴的設(shè)計能力,其難度不亞于沒有任何多態(tài)特性的C語言了。可以這么說,繼承樹一旦出現(xiàn)虛繼承這個怪胎,整體架構(gòu)就有大問題,毫無疑問,iostream也不例外。不過,如果沒有那么多的動態(tài)要求,好比gui框架的變態(tài)需求,嚴格以接口作為耦合對象,輔以function,也即是委托,又可以應(yīng)付多起碼15%的局面。其實,必須要用到virtual函數(shù)的時候,將virtual函數(shù)hi起來,那種感覺非常清爽,很多人談virtual色變,大可不必。C#和java還加上垃圾回收和反射,這個比例可以放大很多。在這種層次下,接口最大的問題是,就好像成員函數(shù),是封閉的。一個class定義完畢,其能支持的interface的數(shù)量也就定死了,不能再有任何修改。interface可以說是一個class的對外的開放功能,現(xiàn)實世界中,一種東西的對外功能并不是一開始就定死了的,其功能也在后來慢慢挖掘。但是,C++/java/C#的接口就不是這樣,class定義完畢,就沒有任何潛力可言了。明明看到某些class的能力可以實現(xiàn)某些接口,甚至函數(shù)簽名都一樣,對不起,誰讓你當(dāng)初不實現(xiàn)這個接口。對此,各種動態(tài)語言閃亮登場,或mixing或鴨子類型。接口還有另一尷尬之處,比如,鳥實現(xiàn)了會飛的接口,鴨子企鵝也繼承了鳥,自然也就繼承了會飛的接口,沒辦法不繼承。面對著一個需要IFlyable參數(shù)的函數(shù),我們順利的傳一只企鵝進去,然后企鵝再里面始終飛不起來,就算企鵝在被要求飛的時候,拋出異常,也不過自欺欺人。這種悲劇,就好像有些人很會裝逼,最后一定會壞事。搞出接口這種破事,就是為了讓編譯器做類型檢查的。又有人說,bird應(yīng)當(dāng)分為兩類,會飛的和不會飛的,這的確能解決飛行的尷尬。但是,有很多鳥具備捉蟲蟲的能力,然后又有那么一小撮鳥不會捉蟲只會捉魚,難道又要依據(jù)捉蟲能力再劃分出鳥類。于是鳥類的繼承樹越長越高,畫面越來越美。這分明就是語言能力的不足,把問題交給猿猴了。請謹記,接口就是一個強有力的契約,既然實現(xiàn)了一個接口,就說明有能力做好相關(guān)的事情。再說,既然interface這么重要,于是我們再設(shè)計class的時候,就自然而然把精力放在interface這個對外交流媒介的手段之上了,而忽視了class本身的推敲。class最重要的事情就是全心全意做好獨立完整最小化的事情,其他什么對外交互不要理會。一個class如果能夠完整的封裝一個清晰的概念,后面不管怎么重構(gòu),都可以保留下來。但是,interface會分散這種設(shè)計。接口的悲劇就在于企圖頂多以90分的能力去干一百分的事情,并且還以為自己可以做得好,硬上強干,罔顧自身的極限。往往做了90%的工作量,事情恰恰就壞在剩下來的10%上。
                  于是,狗語言走上另一條邪路,鴨子類型。只要class,不,是struct,這種獨特關(guān)鍵字的品味,只要某個struct能夠完全實現(xiàn)某個interface的所有函數(shù),就默認其實現(xiàn)了這個接口。并且,狗語言還禁止了繼承,代之以“組合”這個高大上的名詞了,但是,細究一下語義和內(nèi)存布局(忽略虛函數(shù)表指針),你媽的,不就是一個沒有virtual繼承的弱多繼承嗎?顯式的繼承消失了,隱式的繼承還存在的,好了,還不讓你畫出繼承樹關(guān)系圖,高高興興對外宣稱沒有繼承了,沒有繼承并不表示繼承的問題木有存在。但是,因為狗語言的成員函數(shù)方法可以定義在class,不,struct外面,其擴展性就非常好了,對于一個interface,有哪些方法,本struct不存在,就地給它定義出來,然后,struct就輕松的實現(xiàn)了該接口,即使原來的struct不支持該接口,以后也有辦法讓它支持,很好很強大。之所以能做到這一點,那是因為狗語言的虛函數(shù)表是動態(tài)生成的。小心的使用接口各種名字,部分人應(yīng)該狗語言用起來會相當(dāng)愉快。可是,你媽,不同接口的函數(shù)名字不能一樣啊,或者說,同一個函數(shù)的名字不能出現(xiàn)在不同接口中。不過,這個問題并不難,不就是不一樣的名字嗎,c語言中此等大風(fēng)大浪猿猴誰沒有見識過。對于狗語言,不想做太多評斷,只是,其擴展性確實不錯,非侵入式的成員函數(shù)和非侵入式的接口,理應(yīng)能更好地應(yīng)付接口實現(xiàn)這種多態(tài)方式,只是,編譯器在上面所做的類型約束想必會不如后者,重構(gòu)什么的,想必不會很方便。自由上去了,約束自然也下來了。聽起來挺美,但是內(nèi)里也有些地方要推敲,反正老朽不喜歡,以后也不大會用上,當(dāng)然,給money自然會用,給money不搞c++都沒問題。老朽還是比較喜歡虛函數(shù)的接口,更何況c++通過奇技淫巧也能非侵入式的給class添加接口。在靜態(tài)語言中搞這種鴨子類型的動態(tài)語言接口,顯得有點不倫不類。
                  然后就是com接口的面向?qū)ο螅耆崛ゾ幾g器對接口類型的約束,自然能換來更大的自由。由于com的語言通用性目標(biāo),所以搞得有點復(fù)雜,但是com背后的理念也挺純潔。老朽猜測com好似是要在靜態(tài)語言上搭建出一個類似于動態(tài)語言的運行平臺,外加語言通用性。其契約很明確,操作對象前時,必須先查詢到對象支持的接口,進而調(diào)用接口的函數(shù)。這里有意思的地方在于面對著一個com對象,你居然沒有辦法知道到它究竟實現(xiàn)了多少接口。
                  最后就是消息發(fā)送了,其能力之強大,誰用誰知道。原則上講,可以看成對象擁有的虛函數(shù)表的方法無窮多,又可以把每一條消息看成一個接口,那么,對象可能就實現(xiàn)了無窮多的接口。你說,面對著這樣對象,還有什么做不出來呢。真用上消息發(fā)送這種隱藏?zé)o數(shù)間接層,就沒有什么軟件問題解決不了的。任何軟件問題不就是通過引入間接層來解決的嘛。現(xiàn)在用上消息發(fā)送這種怪物,就問你怕不怕。沒有免費午餐,自然要付出類型安全的危險和性能上的損失。

            posted on 2016-05-10 22:40 華夏之火 閱讀(1668) 評論(3)  編輯 收藏 引用 所屬分類: 編程語言雜談

            評論

            # re: 消息發(fā)送雜談 2016-05-11 12:18 Richard Wei

            這里有意思的地方在于面對著一個com對象,你居然沒有辦法知道到它究竟實現(xiàn)了多少接口。微軟自己也也意識到了這個問題, 于是WinRT里就有了IInspectable::GetIids, https://msdn.microsoft.com/en-us/library/br205822(v=vs.85).aspx  回復(fù)  更多評論   

            # re: 消息發(fā)送雜談 2016-05-13 14:49 天下

            好文,贊。  回復(fù)  更多評論   

            # re: 消息發(fā)送雜談[未登錄] 2016-07-07 09:27 x

            mark。精品文章,收藏之  回復(fù)  更多評論   

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(6)

            隨筆分類

            隨筆檔案

            搜索

            積分與排名

            最新評論

            閱讀排行榜

            評論排行榜

            99久久精品九九亚洲精品| 久久午夜电影网| 2019久久久高清456| 中文字幕久久久久人妻| 无码国内精品久久人妻| 青青草国产精品久久| 亚洲国产成人乱码精品女人久久久不卡| 日本精品久久久久久久久免费| 99精品国产99久久久久久97| 久久―日本道色综合久久| 麻豆av久久av盛宴av| 国产成人精品久久| 中文字幕无码精品亚洲资源网久久| 久久狠狠色狠狠色综合| 精品久久亚洲中文无码| 国产精品嫩草影院久久| 少妇久久久久久久久久| 伊人色综合九久久天天蜜桃| 国产精品成人无码久久久久久| 久久久这里有精品| 无夜精品久久久久久| 日本三级久久网| 国产精品久久久久久久久| 狠狠综合久久综合88亚洲| 开心久久婷婷综合中文字幕| 热久久国产精品| 青青青国产成人久久111网站| 国产精品久久久久久福利漫画 | 日本精品久久久久中文字幕| 狠狠色综合网站久久久久久久高清| 亚洲国产精品狼友中文久久久| 国产成人精品久久亚洲高清不卡| 996久久国产精品线观看| 久久99精品久久久久久动态图| 亚洲欧美伊人久久综合一区二区 | 狠狠色丁香久久婷婷综合_中 | 午夜人妻久久久久久久久| 久久精品国产男包| 亚洲中文久久精品无码| 亚洲国产精品无码久久久不卡 | 久久综合亚洲色HEZYO社区|