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

            sherrylso

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

                    C++之父Bjarne stroustrup曾經(jīng)說過:不需要了解所有的c++細(xì)節(jié),也能夠?qū)懗龊玫腸++程序;不應(yīng)該注重語言方面的特征,而應(yīng)該注重軟件設(shè)計(jì)技術(shù)本身。很顯然,我的這篇文章,與這兩句話背道而馳:).的確,我們程序員,不應(yīng)該把精力放在c++本身語言的特征上,而是應(yīng)該思考軟件設(shè)計(jì)技術(shù)本身。那么,在我們需要提高對c++理解的同時(shí),是不是我們從下面幾個(gè)方面為著眼點(diǎn)
            1) 從編譯原理的角度
            2) 從技術(shù)需求的角度
            3) 從軟件設(shè)計(jì)技術(shù)的角度
            從以上的幾個(gè)角度,來重新審視c++一些晦澀語法,或許,我們能從中獲益。在這里,我要說的是,我們不單單是要記住這些c++語言特性怎么樣的使用,而是應(yīng)該知道這些語言特性背后隱藏的故事,以便于我們更深層次地理解c++,理解軟件設(shè)計(jì)。
            一、子類通過函數(shù)名字隱藏父類函數(shù)。
            如下例:

            class Base
            {
            public:
             virtual 
            void f(int x);
            }
            ;
            class Derived: public Base
            {
            public:
             virtual 
            void f(double* pd);
            }
            ;
            int main()
            {
              Derived
            * pd = new Derived();
              pd
            ->f(10); //compile error!!!
            }

                     當(dāng)我們編譯pd->f(10)操作時(shí),編譯器報(bào)錯(cuò)。按照我們常規(guī)的理解是:父類的函數(shù)void f(int x)與子類的函數(shù)void f(double*pd),由于參數(shù)類型不同,其函數(shù)簽名也是不一樣的,按照這樣的邏輯,在這個(gè)類繼承體系中,這兩個(gè)函數(shù)完全應(yīng)該是互不隱藏的,我們完全可以認(rèn)為是符合overloaded規(guī)則的兩個(gè)函數(shù)。
                    但是,在c++里,子類通過函數(shù)名字隱藏父類函數(shù),而不是通過函數(shù)簽名!c++給出的解釋也是合理的:試想一種情況:你使用了別人寫的類庫,繼承其中的某個(gè)類,寫了你自己的子類。
            如上面的例子,你的子類就是Derived,而類庫中的父類就是Base.當(dāng)你根本不知道在父類中還有這樣一個(gè)f(int x)函數(shù)時(shí),在調(diào)用子類Derived的f函數(shù)時(shí),你犯了錯(cuò)誤,參數(shù)類型傳成了int類型(或者不是你犯的錯(cuò)誤,編譯器幫你自動轉(zhuǎn)化為int類型),結(jié)果是:程序可以正常運(yùn)行,但是,執(zhí)行的結(jié)果卻不是你所期望的,是f(int x)調(diào)用,而不是你自己的實(shí)現(xiàn):f(double* pd)調(diào)用!
                     這就是c++為什么通過函數(shù)名字隱藏父類函數(shù)的原因。
                    說到這里,我們需要補(bǔ)充幾句:雖然c++在語言層面上給我們提供了這樣的保證,但是,子類hide父類的函數(shù),這是一個(gè)非常不好的設(shè)計(jì)。從OO的角度出發(fā),應(yīng)該講求的是Liskov Substitution Principle。即:suntypes must be substitutable fro their base types.很顯然,當(dāng)hide行為發(fā)生時(shí),從接口的角度來講,子類與父類是不能互為替代的。父類的protected or public的方法,應(yīng)該很自然地由其所有子類所繼承,而不是被隱藏。隱藏行為的發(fā)生,相當(dāng)于在這套繼承體系中開的一個(gè)后門。很顯然,C++幫助我們自動隱藏了父類的方法,但是,作為程序開發(fā)的我們,應(yīng)該意識到這一點(diǎn),也應(yīng)該避免這樣的設(shè)計(jì)。
            二、c++的per-class allocator語法規(guī)則
                      在D&E of C++一書中,Stroustrup給出了幾點(diǎn)c++提供per-class allocator的理由,這些理由也是我們使用class level的allocator的原因,所以,有必要我們總結(jié)一下:
            第一、許多程序應(yīng)用,需要在運(yùn)行的過程中,大量地Create和Delete對象。這些對象,諸如:tree nodes,linked list nodes,messages等等。如果在傳統(tǒng)的heap完成這些對象的創(chuàng)建,銷毀,由于大量的內(nèi)存申請,釋放,勢必會造成內(nèi)存碎片。這種情況下,我們需要對內(nèi)存分配進(jìn)行細(xì)粒度的控制。
            第二、一些應(yīng)用需要長時(shí)間跑在內(nèi)存受限的裝置上,這也需要我們對內(nèi)存分配進(jìn)行細(xì)粒度的控制,而不是無限制地分配,釋放。
            主要基于以上的兩點(diǎn),c++提供了per-class allocator語言支持。
            如下例:

            class X
            {
            public:
              
            void* operator new(size_t sz); //allocate sz bytes
              void  operator delete(void* p) //free p;
            }
            ;

                  new操作符函數(shù)負(fù)責(zé)對象X的內(nèi)存分配。對這樣一個(gè)語法規(guī)則,我們好奇的是,為什么聲明了一個(gè)我們從來都不使用的參數(shù)size_t sz.我們的使用語法如下: X* px = new X;
            C++也給出了解釋:per-class allocator機(jī)制將適用整個(gè)類的繼承體系。例如:

            class Y: public X //ojects of class Y are also allocated using X::operator new
            {
              
            //
              
            // 
            }
            ;

                    對于子類Y,其內(nèi)存分配函數(shù)也是X::operator new()。但是,在這里,內(nèi)存分配的大小,不應(yīng)該是sizeof(X),而是sizeof(Y).問題的關(guān)鍵在這里:C++通過提供多余的參數(shù)size_t sz,而給開發(fā)者提供了更大的靈活性,也即:per-class allocator是面向類的繼承體系的內(nèi)存管理機(jī)制,而不單單是面向單個(gè)類。
            三、Koenig Lookup機(jī)制。
                    大家對Andrew Koenig應(yīng)該很熟悉,c++大牛,是AT&T公司Shannon實(shí)驗(yàn)室大規(guī)模編程研究部門中的成員,同時(shí)他也是C++標(biāo)準(zhǔn)委員會的項(xiàng)目編輯。他擁有超過30年的編程經(jīng)驗(yàn),其中有15年的C++使用經(jīng)驗(yàn)。
                    Koenig Lookup,就是以Andrew Koenig命名的查找規(guī)則。在看這個(gè)定義之前,我們先弄清楚函數(shù)所在的域的分類,一般來講,分為:
            1:類域(函數(shù)作為某個(gè)類的成員函數(shù)(靜態(tài)或非靜態(tài)))
            2:名字空間域
            3:全局域(即C++默認(rèn)的namespace)
                    而Koenig Lookup機(jī)制,就是當(dāng)編譯器對無限定域的函數(shù)調(diào)用進(jìn)行名字查找時(shí),除了當(dāng)前名字空間域以外,也會把函數(shù)參數(shù)類型所處的名字空間加入查找的范圍。
            如下例:

            #include <iostream>
            using namespace std;
            namespace Koenig
            {
                
            class MyArg
                
            {
                
            public:
                     ostream
            & print(ostream& out) const
                     
            {
                        out
            <<"this is MyArg."<<endl;
                     }

                }
            ;
             
                inline ostream
            & operator<<(ostream& out, const MyArg& myArg)
                
            {
                     
            return myArg.print(out);
                }

            }

             
            int main()
            {
                Koenig::MyArg myArg;
                cout
            <<myArg;
                
            return 0;
            }

                   如上的代碼,使用operator<<操作符函數(shù),打印對象的狀態(tài),但是函數(shù)ostream& operator<<(ostream& out, const MyArg& myArg) 的定義域是處于名字空間Koenig中,為什么編譯器在解析main函數(shù)(全局域)里面的operator<<調(diào)用時(shí),它能夠正確定位到Koenig名字空間里面的operator<<?這是因?yàn)楦鶕?jù)Koenig查找規(guī)則,編譯器需要把參數(shù)類型MyArg所在的名字空間Koenig也加入對ostream& operator<<(ostream& out, const MyArg& myArg) 調(diào)用的名字查找范圍中。
                   
            如果沒有Koenig查找規(guī)則,我們就無法直接寫cout<<myArg;,而是需要寫類似Koenig::operator<<(std::cout, myArg); 這樣的代碼(使用完全限定名)。這樣的結(jié)果是,即不直觀也不方便。

                    其實(shí)在C++里,提供了很多類似于Koenig查找規(guī)則的機(jī)制,以保證程序語法上的簡潔,明了。例如:許多的操作符函數(shù),COPY構(gòu)造函數(shù)。而這些,也是我們寫出專業(yè)的C++程序的基本。
            未完待續(xù):)

             

             


             

            posted on 2007-11-11 14:56 愛上龍卷風(fēng) 閱讀(4648) 評論(26)  編輯 收藏 引用

            Feedback

            # re: c++晦澀語法背后的故事(一) 2007-11-11 15:16 lovedday
            關(guān)于

            class Base
            {
            public:
            virtual void f(int x);
            };
            class Derived: public Base
            {
            public:
            virtual void f(double* pd);
            };
            int main()
            {
            Derived* pd = new Derived();
            pd->f(10); //compile error!!!
            }

            很顯然編譯報(bào)錯(cuò)是對的,因?yàn)楹瘮?shù)原型不一樣,所以不構(gòu)成overwrite。

            既然不構(gòu)成overwrite,那么你調(diào)用的就是Derived中的f函數(shù),編譯器檢查后發(fā)現(xiàn)沒有匹配的函數(shù),當(dāng)然報(bào)錯(cuò)。

            至于后面的解釋個(gè)人認(rèn)為不著調(diào)。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 15:25 <a href=http://minidx.com>minidxer</a>
            同意lovedday的觀點(diǎn)  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 15:25 lovedday
            #include <iostream>
            using namespace std;
            namespace Koenig
            {
            class MyArg
            {
            public:
            ostream& print(ostream& out) const
            {
            out<<"this is MyArg."<<endl;
            }
            };

            inline ostream& operator<<(ostream& out, const MyArg& myArg)
            {
            return myArg.print(out);
            }
            }

            int main()
            {
            Koenig::MyArg myArg;
            cout<<myArg;
            return 0;
            }

            這種代碼基本上屬于濫用運(yùn)算符重載,實(shí)際上C++的不少機(jī)制都會導(dǎo)致被濫用,結(jié)果就是產(chǎn)生晦澀難懂且充滿bug的垃圾代碼,當(dāng)然這種代碼做為反面教材還是不錯(cuò)的,但若是在項(xiàng)目中使用這種代碼,那將是惡夢。
              回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 15:29 lovedday
            個(gè)人認(rèn)為盡量少重載運(yùn)算符,比如printf就比<<好用,實(shí)在沒有什么必要去重載<<,使用函數(shù)更好。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 15:34 lovedday
            ps,說這些沒別的意思,只是說在實(shí)際項(xiàng)目中不應(yīng)該這么使用運(yùn)算符重載,當(dāng)然sherrylso只是為了說明C++語法而編寫這些代碼。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 15:37 lovedday
            C++里還有函數(shù)重載和參數(shù)默認(rèn)值,實(shí)際上這兩個(gè)機(jī)制是滋生bug的溫床,如果配合多態(tài),將會導(dǎo)致十分難以理解的行為,所以別用函數(shù)重載和參數(shù)默認(rèn)值。

            看看這個(gè)例子,絕對讓你抓狂,猜猜看輸出的i和j值是多少?

            #include <stdio.h>

            class PARENT
            {
            public:
            virtual int doIt( int v, int av = 10 )
            {
            return v * v;
            }
            };

            class CHILD : public PARENT
            {
            public:
            int doIt( int v, int av = 20 )
            {
            return v * av;
            }
            };

            int main()
            {
            PARENT *p = new CHILD();

            int i = p->doIt(3);
            printf("i = %d\n", i);

            CHILD* q = new CHILD();

            int j = q->doIt(3);
            printf("j = %d\n", j);

            return 0;
            }  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 16:20 foobar
            @lovedday
            class Base
            {
            public:virtual void f(int x);
            };
            class Derived: public Base
            {
            public:virtual void f(double* pd);
            };
            int main()
            {
            Derived* pd = new Derived();
            pd->f(10); //compile error!!!
            }

            這個(gè)例子只有聲明沒有定義,編譯肯定有錯(cuò)
            但是
            在c++里,子類通過函數(shù)名字隱藏父類函數(shù),而不是通過函數(shù)簽名!

            這個(gè)分析應(yīng)該沒什么問題
            子類確實(shí)通過函數(shù)名字隱藏了父類的函數(shù)
              回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 16:38 lovedday
            在c++里,子類通過函數(shù)名字隱藏父類函數(shù),而不是通過函數(shù)簽名!

            這個(gè)分析應(yīng)該沒什么問題
            子類確實(shí)通過函數(shù)名字隱藏了父類的函數(shù)

            -------------------------------------------------------

            你的這個(gè)論斷顯然是錯(cuò)的。

            #include <stdio.h>

            class Base
            {
            public:
            virtual void f(int x)
            {
            printf("call base f function\n");
            }
            };

            class Derived: public Base
            {
            public:
            virtual void f(double pd)
            {
            printf("call derived f function\n");
            }
            };

            int main()
            {
            Base* pb = new Derived;
            pb->f(10.5);

            return 0;
            }

            輸出:

            call base f function  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 16:47 foobar
            @lovedday
            pb是個(gè)父類指針,所以調(diào)用父類的f

            Derived* pb = new Derived;
            pb->f(10);
              回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 17:00 lovedday
            @foobar

            很懷疑你是不是C++沒學(xué)好。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 17:05 lovedday
            #include <stdio.h>

            class Base
            {
            public:
            virtual void f(int x)
            {
            printf("call base f function\n");
            }
            };

            class Derived: public Base
            {
            public:
            virtual void f(double pd)
            {
            printf("call derived f function\n");
            }
            };

            int main()
            {
            Base* pb = new Derived;
            pb->f(10.5);

            return 0;
            }

            輸出:

            call base f function

            你說只要函數(shù)名稱相同子類就可以覆蓋父類函數(shù)的行為,但很顯然,這個(gè)例子說明了僅函數(shù)名稱相同是無法覆蓋的。如果你沒看懂,是不是說明還沒把多態(tài)搞清楚?  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 17:07 foobar
            @lovedday
            上面說的不夠確切
            你c++學(xué)的好,知道多態(tài)這個(gè)概念,但是c++有很多缺點(diǎn)
            樓主的那個(gè)例子,你在理解上是有誤的
            子類的確實(shí)用函數(shù)簽名hide了父類的函數(shù)
            所以你調(diào)用f的時(shí)候,肯定調(diào)用了f(double)

            但是用dynamic type的時(shí)候,情況就不是這樣了

            nt main()
            {
            Base* pb = new Derived;
            pb->f(10.5);

            return 0;
            }

            輸出當(dāng)然是base
            但是絕對不是子類有個(gè)函數(shù)輸出base
            而確實(shí)調(diào)用了父類的函數(shù)

              回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 17:10 foobar
            @lovedday
            多態(tài)是c++的一個(gè)特性 但是 c++遠(yuǎn)比這個(gè)復(fù)雜
            你看看下面的代碼,希望能明白我的意思

            #include <iostream>
            class Base
            {
            public:
            virtual void foo() { std::cout << "Base::foo\n"; }
            void foo(int) { std::cout << "Base::foo(int)\n"; }
            };

            class Derived : public Base
            {
            public:
            void foo() { std::cout << "Derived::foo\n"; }
            };

            int main()
            {
            Base b;
            b.foo(); // Base's foo() is called
            b.foo(3); // Base's foo(int) is called
            Derived d;
            d.foo(); // Derived's foo() is called. The one in Base is hidden
            d.foo(3); // error, that function is also hidden
            Base &ref = d;
            ref.foo(); // Derived's foo() is called. It overrides the Base version
            ref.foo(3); // Base's foo(int) is called
            }  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-11 17:45 lovedday
            @foobar

            謝謝,我明白了作者的意思,但實(shí)際上正如文章所指出的那樣,這是一個(gè)糟糕的設(shè)計(jì),實(shí)際上這些都導(dǎo)致了含混不清的語義和容易出錯(cuò)的代碼,所以我說不要去重載函數(shù)。

            C++的復(fù)雜很大一部分原因是因?yàn)槠湓愀獾脑O(shè)計(jì)。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-12 12:50 pzy
            我想可以這么總結(jié):
            派生類中的函數(shù)會override基類中與它具有相同簽名的虛函數(shù),同時(shí)會hide基類中所有與它具有相同名稱(而非簽名)的非虛函數(shù)。無論如何,派生類函數(shù)不會overload基類函數(shù)。

            lovedday提供的那個(gè)例子(參數(shù)默認(rèn)值)的結(jié)果實(shí)在是匪夷所思,仿佛此時(shí)參數(shù)默認(rèn)值也是簽名的一部分。誰能解釋一下啊?  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一)[未登錄] 2007-11-14 00:43 romangol
            @pzy
            下面是對應(yīng)函數(shù)調(diào)用的反匯編代碼中重要的幾行
            int i = p->doIt(3);
            0040133B MOV DWORD PTR SS:[ESP+8],0A ;壓入默認(rèn)參數(shù)10
            00401343 MOV DWORD PTR SS:[ESP+4],3 ;壓入調(diào)用參數(shù)3
            0040134E MOV DWORD PTR SS:[ESP],EAX
            00401351 MOV EAX,DWORD PTR DS:[EDX]
            00401353 CALL EAX

            int j = q->doIt(3);
            00401389 MOV DWORD PTR SS:[ESP+8],14 ;壓入默認(rèn)參數(shù)20
            00401391 MOV DWORD PTR SS:[ESP+4],3 ;壓入調(diào)用參數(shù)3
            00401399 MOV EAX,DWORD PTR SS:[EBP-10]
            0040139C MOV DWORD PTR SS:[ESP],EAX
            0040139F MOV EAX,DWORD PTR DS:[EDX]
            004013A1 CALL EAX

            注意到兩個(gè)默認(rèn)參數(shù)是在編譯時(shí)就已經(jīng)寫死了,也就是說編譯器在編譯器就為兩個(gè)doIt調(diào)用分別決議了默認(rèn)參數(shù),然而在運(yùn)行期它們卻是通過動態(tài)的方式
            Call EAX
            來運(yùn)行,實(shí)際上在調(diào)試中也可以看到它們調(diào)用的都是子類的doIt函數(shù)(調(diào)用地址是相同的)。

            我個(gè)人的理解是,虛函數(shù)的調(diào)用是通過虛函數(shù)表來完成的,故父類指針可以調(diào)用子類的函數(shù),然而默認(rèn)參數(shù)作為對象內(nèi)存模型的一部分,是分別屬于不同的對象的,故編譯器為父類指針的函數(shù)調(diào)用還是賦予了父類對象的參數(shù)值。

            請高手們指教  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-14 00:45 march rabbit
            贊~  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-15 22:11 愛上龍卷風(fēng)
            @foobar
            非常感謝foobar對本文詳盡的解釋。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-15 23:00 foobar
            @愛上龍卷風(fēng)

            不要感謝foobar,還是感謝google和c++編程思想吧。。。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-11-16 12:30 pzy
            @romangol

            哈哈~我不太懂匯編,但應(yīng)該明白你的意思了:lovedday的例子中,PARENT指針和CHILD指針調(diào)用的都是CHILD::doIt(),只不過在調(diào)用之前(編譯階段),編譯器已經(jīng)它們填上默認(rèn)參數(shù)值了,分別是10和20。

            也就是說虛函數(shù)調(diào)用有多態(tài)性,而默認(rèn)參數(shù)是靜態(tài)的,不存在運(yùn)行時(shí)決策(如你所說,默認(rèn)參數(shù)是在編譯時(shí)就已經(jīng)寫死了)。

            這個(gè)例子是有意設(shè)計(jì)成讓PARANT::doIt()與CHILD::doIt()的函數(shù)體相同,才有迷惑人的效果。

            PS. 由此我進(jìn)一步理解了C#為什么不支持默認(rèn)參數(shù)值,也不鼓勵(lì)在庫中使用公開常量。默認(rèn)參數(shù)值與常量都是在編譯后就“死”的,這個(gè)事實(shí)的后果是,修改庫后,用戶代碼需要重編譯。  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2007-12-27 22:06 秦歌
            頂一下!  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2008-01-07 22:42 abettor.org
            大家分析的都很好,學(xué)習(xí)了!  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2008-07-03 14:12 md6600
            C++代碼本來就很明了精簡。 只不過 人比較懶惰,所以越來越簡。就會這樣咯。 寫句注釋嘛 有多難呢111  回復(fù)  更多評論
              

            # What a joy to find such clear thinikng. Thanks for posting! 2011-05-26 10:20 Mateen
            What a joy to find such clear thinikng. Thanks for posting!  回復(fù)  更多評論
              

            # re: c++晦澀語法背后的故事(一) 2013-02-27 11:10 bluemei
            用重寫來彌補(bǔ)一下:
            class Base
            {
            public:
            virtual void f(){
            TRACE("Base f()\n");
            }
            virtual void f(int i){
            TRACE("Base f(int)\n");
            }
            };
            class Child : public Base
            {
            public:
            virtual void f(){
            TRACE("Child f()\n");
            }
            virtual void f(int i){
            __super::f(i);
            }
            };

            Child *p=new Child();
            p->f();
            p->f(10);  回復(fù)  更多評論
              


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            国产精品九九久久精品女同亚洲欧美日韩综合区 | 国产精品久久久久久福利69堂| 亚洲av伊人久久综合密臀性色| 五月丁香综合激情六月久久| 久久精品国产亚洲AV无码娇色| 久久免费精品视频| 久久婷婷色综合一区二区| 久久婷婷成人综合色综合| 99久久亚洲综合精品网站| 亚洲精品97久久中文字幕无码| 亚洲αv久久久噜噜噜噜噜| 亚洲国产精品婷婷久久| 久久久久久亚洲精品影院| 亚洲日本va中文字幕久久| 亚洲伊人久久大香线蕉苏妲己| 亚洲性久久久影院| 久久99国产精品99久久| 国产成人无码精品久久久性色 | 久久国产精品免费一区| 丁香色欲久久久久久综合网| 国产A级毛片久久久精品毛片| 久久99久久99精品免视看动漫| 国产精品久久久99| 国产精品久久久久jk制服| 久久婷婷是五月综合色狠狠| 99久久久久| 亚洲狠狠久久综合一区77777| 久久水蜜桃亚洲av无码精品麻豆 | 久久人人爽人爽人人爽av| 99久久精品国产麻豆| 久久久国产乱子伦精品作者| 久久久精品国产免大香伊| 久久夜色撩人精品国产| 欧美午夜A∨大片久久| 久久毛片一区二区| 亚洲午夜无码久久久久小说| 久久99九九国产免费看小说| 久久精品国产亚洲av瑜伽| 久久av高潮av无码av喷吹| 久久人人爽人人爽AV片| 亚洲精品99久久久久中文字幕|