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

            巢穴

            about:blank

            [轉(zhuǎn)]《深度探索C++對(duì)象模型》讀書(shū)筆記[一]

            《深度探索C++對(duì)象模型》讀書(shū)筆記                                                                              

            前 言 Stanley B.Lippman
            1.   任何對(duì)象模型都需要的三種轉(zhuǎn)換風(fēng)味:

            ü        與編譯器息息相關(guān)的轉(zhuǎn)換

            ü        語(yǔ)言語(yǔ)義轉(zhuǎn)換

            ü        程序代碼和對(duì)象模型的轉(zhuǎn)換

            2.   C++對(duì)象模型的兩種解釋

            ü        語(yǔ)言中直接支持面向?qū)ο蟪绦蛟O(shè)計(jì)的部分

            ü        對(duì)于各種支持的底層實(shí)現(xiàn)機(jī)制

            3.   C++ class的完整virtual functions在編譯時(shí)期就固定下來(lái)了,程序員沒(méi)有辦法在執(zhí)行期動(dòng)態(tài)增加或取代其中某一個(gè)。這使得虛擬函數(shù)調(diào)用操作得以有快速的派送結(jié)果,付出的卻是執(zhí)行期的彈性。

            4.   目前所有編譯器對(duì)于virtual function的實(shí)現(xiàn)都是使用各個(gè)class專屬的virtual table,大小固定,并且在程序執(zhí)行前就構(gòu)造好了。

            5.   C++對(duì)象模型的底層機(jī)制并未標(biāo)準(zhǔn)化,它會(huì)因?qū)崿F(xiàn)品(編譯器)和時(shí)間的變動(dòng)而不同。

            2002-6-23

            關(guān)于對(duì)象 Object Lessons
            1.1 C++對(duì)象模式
            1.   C++在布局以及存取時(shí)間上主要的額外負(fù)擔(dān)是由virtual引起的,包括virtual function機(jī)制和virtual base class 機(jī)制,還有一些發(fā)生在“一個(gè)derived class和其第二或后繼之base class的轉(zhuǎn)換”上的多重繼承。

            2.   在C++對(duì)象模型中,nonstatic data members被配置于每一個(gè)class object之內(nèi),static data members則被存放在所有的class object之外,static和nonstatic function members也被放在所有的class object之外,virtual functions則以兩個(gè)步驟支持:每個(gè)class產(chǎn)生一堆指向virtual functions的指針,放在virtual table (vtbl)中;每個(gè)class object被添加一個(gè)指針vptr,指向相關(guān)的virtual table。每個(gè)class所關(guān)聯(lián)的type_info object也經(jīng)由vtbl指出,通常是放在vtbl的第一個(gè)slot處。vptr由每一個(gè)class的construtor、destructor以及copy assignment operator自動(dòng)完成。以上模型的主要優(yōu)點(diǎn)在于空間和存取時(shí)間的效率,主要缺點(diǎn)是,只要應(yīng)用程序所用到的class object的nonstatic data members有所修改,那么應(yīng)用程序代碼就必須重新編譯。

            3.   C++最初所采用的繼承模型并不運(yùn)用任何間接性,base class subobject的data members直接放置于derived class object中。優(yōu)點(diǎn)是提供對(duì)base class members緊湊且高效的存取,缺點(diǎn)是base class members的任何改變,都將導(dǎo)致使用其derived class 的object的應(yīng)用程序代碼必須重新編譯。

            4.   virtual base class的原始模型是在class object中為每一個(gè)有關(guān)聯(lián)的virtual base class加上一個(gè)指針,其他演化出來(lái)的模型不是導(dǎo)入一個(gè)virtual base class table,就是擴(kuò)充原已存在的vtbl,用以維護(hù)每一個(gè)virtual base class的位置。

            1.2關(guān)鍵詞所帶來(lái)的差異
            1.   可以說(shuō)關(guān)鍵詞struct的使用伴隨著一個(gè)public接口的聲明,也可以說(shuō)它的用途只是為了方便C程序員遷徙至C++部落。

            2.   C++中凡處于同一個(gè)access section的數(shù)據(jù),必定保證以聲明次序出現(xiàn)在內(nèi)存布局中,然而被放在多個(gè)access sections中的各筆數(shù)據(jù)排列次序就不一定了。同樣,base classes和derived classes的data members的布局也沒(méi)有誰(shuí)先誰(shuí)后的強(qiáng)制規(guī)定。

            3.   組合composition而非繼承才是把C和C++結(jié)合在一起的唯一可行方法。

            1.3對(duì)象的差異
            1.   C++程序設(shè)計(jì)模型支持三種程序設(shè)計(jì)典范programming paradigms:

            ü          程序模型procedural model

            ü          抽象數(shù)據(jù)類型模型abstract data type model, ADT

            ü          面向?qū)ο髷?shù)據(jù)模型object-oriented model,OO

            2.   雖然可以直接或間接處理繼承體系中的一個(gè)base class object,但只有通過(guò)pointer或reference的間接處理,才能支持OO程序設(shè)計(jì)所需的多態(tài)性質(zhì)。

            3.   C++中,多態(tài)只存在于public class體系中,nonpublic的派生行為以及類型為void*的指針可以說(shuō)是多態(tài),但它們沒(méi)有被語(yǔ)言明白地支持,必須由程序員通過(guò)顯示的轉(zhuǎn)型操作來(lái)管理。

            4.   C++以下列方法支持多態(tài):

            ü          經(jīng)由一組隱含的轉(zhuǎn)化操作,如把一個(gè)derived class指針轉(zhuǎn)化為一個(gè)指向其public base type的指針;

            ü          經(jīng)由虛擬機(jī)制;

            ü          經(jīng)由dynamic_cast和typeid運(yùn)算符。

            5.   多態(tài)的主要用途是經(jīng)由一個(gè)共同的接口來(lái)影響類型的封裝,這個(gè)接口通常被定義在一個(gè)抽象的base class中。這個(gè)接口是以virtual function機(jī)制引發(fā)的,它可以在執(zhí)行期根據(jù)object的真正類型解析出到底是哪一個(gè)函數(shù)實(shí)體被調(diào)用。

            6.   一個(gè)class object所需的內(nèi)存,一般而言由以下部分組成:

            ü          nonstatic data members的總和大小;

            ü          任何由于alignment需求而填補(bǔ)上去的空間;

            ü          為支持virtual而由內(nèi)部產(chǎn)生的任何額外負(fù)擔(dān)。

            7.   一個(gè)pointer或reference,不管它指向哪一種數(shù)據(jù)類型,指針本身所需的內(nèi)存大小是固定的。本質(zhì)上,一個(gè)reference通常是以一個(gè)指針來(lái)實(shí)現(xiàn),而object語(yǔ)法如果轉(zhuǎn)換為間接手法,就需要一個(gè)指針。

            8.   指向不同類型之指針的差異,既不在其指針表示法不同,也不在其內(nèi)容不同,而是在其所尋址出來(lái)的object類型不同,亦即指針類型會(huì)教導(dǎo)編譯器如何解釋某個(gè)特定地址中的內(nèi)存內(nèi)容及大小。它們之所以支持多態(tài),是因?yàn)樗鼈儾⒉灰l(fā)內(nèi)存中任何與類型有關(guān)的內(nèi)存委托操作,會(huì)受到改變的只是它們所指向的內(nèi)存的大小和內(nèi)容的解釋方式。

            9.   轉(zhuǎn)型cast操作其實(shí)是一種編譯指令,大部分情況下它并不改變一個(gè)指針?biāo)恼嬲刂罚皇怯绊懕恢赶蛑畠?nèi)存的大小和內(nèi)容的解釋方式。

            10.一個(gè)base class object被直接初始化或指定為一個(gè)derived object時(shí),derived object就會(huì)被切割sliced,以塞入較小的base type內(nèi)存中,多態(tài)于是不再呈現(xiàn)。一個(gè)嚴(yán)格的編譯器可以在編譯時(shí)期解析一個(gè)通過(guò)該object而觸發(fā)的virtual function調(diào)用操作,從而回避virtual機(jī)制。這時(shí),如果virtual function被定義為inline,則會(huì)有效率上的收獲。

            11.C++通過(guò)class的pointer和reference來(lái)支持多態(tài),這種程序設(shè)計(jì)風(fēng)格就是所謂的OO;C++也支持具體的ADT程序風(fēng)格,如今被稱為object-based OB,不支持多態(tài),不支持類型的擴(kuò)充。

            2002-6-25

            構(gòu)造函數(shù)語(yǔ)意學(xué)The Semantics of Constructors
            1.   Jerry Schwarz,iostream函數(shù)庫(kù)建構(gòu)師,曾為了讓cin能夠求得一個(gè)真假值,于是他為它定義了一個(gè)conversion運(yùn)算符operator int()。但在語(yǔ)句cin << intVal中,其行為出乎意料:程序原本要的是cout而不是cin!但是編譯器卻找到一個(gè)正確的詮釋:將cin轉(zhuǎn)型為整型,現(xiàn)在left shift operator <<就可以工作了!這就是所謂的“Schwarz Error”。Jerry最后以operator void *()取代operator int()。

            2.   引入關(guān)鍵詞explicit的目的,就是為了提供程序員一種方法,使他們能夠制止單一參數(shù)的constructor被當(dāng)作一個(gè)conversion運(yùn)算符。其引入是明智的,但其測(cè)試應(yīng)該是殘酷的!

            2.1 Default Constructor的建構(gòu)操作
            1.   global objects的內(nèi)存保證會(huì)在程序激活的時(shí)候被清為0。local objects配置于程序的堆棧中,heap objects配置于自由空間中,都不一定會(huì)被清為0,它們的內(nèi)容將是內(nèi)存上次被使用后的遺跡。

            2.   在各個(gè)不同的版本模塊中,編譯器避免合成出多個(gè)default constructor的方法:把合成的default constructor、copy constructor、assignment copy operator都以inline方式完成。一個(gè)inline函數(shù)有靜態(tài)鏈接,不會(huì)被檔案以外者看到。如果函數(shù)過(guò)于復(fù)雜,不適合做成inline,就會(huì)合成一個(gè)explicit non-inline static實(shí)體。

            3.   以下四種情況,編譯器必須為未聲明constructor的classes合成一個(gè)implicit nontrivial default constructor:帶有default constructor的member class object,帶有default constructor的base class,帶有virtual function,帶有virtual base class。其它各種情況且沒(méi)有聲明任何constructor的classes,它們擁有的是implicit trival default constructors,它們實(shí)際上并不會(huì)被合成出來(lái)。

            4.   編譯器合成implicit nontrivial default constructor,不過(guò)是暗地里作了一些重要的事情以保證程序正確合理地運(yùn)行。如果程序員提供了多個(gè)constructors,但其中都沒(méi)有default constructor,編譯器同樣會(huì)在這些constructors中插入一些相同功能的代碼,這些代碼都將被安插在explicit user code之前。

            2002-6-26

            2.2 Copy Constructor的建構(gòu)操作
            1.   有三種情況,會(huì)以一個(gè)class的內(nèi)容作為另一個(gè)class object的初值:

            ü          對(duì)一個(gè)object作明確的初始化操作,如:someClass obt = obtb;

            ü          一個(gè)object被當(dāng)作參數(shù)交給某個(gè)函數(shù)時(shí),如:foo(obt);

            ü          當(dāng)函數(shù)返回一個(gè)class object時(shí)。

            若class設(shè)計(jì)者明確定義了一個(gè)copy constructor,大部分情況下,該constructor會(huì)被調(diào)用。這可能導(dǎo)致一個(gè)暫時(shí)性的class object的產(chǎn)生或程序代碼的蛻變,或者兩者皆有。

            2.   如果class沒(méi)有提供一個(gè)explicit copy constructor,當(dāng)class object以相同class的另一個(gè)object作為初值時(shí),其內(nèi)部是以所謂的default memberwise initialization手法完成的,即把每一個(gè)內(nèi)建的或派生的data member的值,從一個(gè)object拷貝到另一個(gè)object。不過(guò),它并不會(huì)拷貝其中的member class object,而是以遞歸的方式施行memberwise initialization。

            3.   一個(gè)class object可以從兩種方式復(fù)制得到:初始化和指定,從概念上而言,這兩個(gè)操作分別是以copy constructor和copy assignment operator完成的。

            4.   如果class沒(méi)有聲明一個(gè)copy constructor,就會(huì)有隱含的聲明implicitly declared或隱含的定義implicitly defined出現(xiàn)。C++把copy constructor分為trivial和nontrivial兩種。只有nontrivial的實(shí)體才會(huì)被合成出來(lái)。決定一個(gè)copy constructor是否為trivial的標(biāo)準(zhǔn)在于class是否展現(xiàn)出所謂的“bitwise copy semantics”。

            5.   以下四種情況,一個(gè)class不展現(xiàn)bitwise copy semantics:

            ü          class內(nèi)含一個(gè)member object而后者的class聲明有或被編譯器合成有一個(gè)copy constructor時(shí);

            ü          class繼承自一個(gè)base class而后者存在或被編譯器合成有一個(gè)copy constructor時(shí);

            ü          當(dāng)class聲明了一個(gè)或多個(gè)virtual functions時(shí);

            ü          當(dāng)class派生自一個(gè)繼承串鏈,其中有一個(gè)或多個(gè)virtual base classes時(shí)。

            前兩種情況中,編譯器必須將member或base class的copy constructors調(diào)用操作安插到被合成的copy constructor中。

            6.   一旦一個(gè)class object中必須引入vptr,編譯器就必須為它的vptr正確地設(shè)置好初值。此時(shí),該class就不再展現(xiàn)bitwise semantics。

            7.   當(dāng)一個(gè)base class object以其derived class object內(nèi)容作初始化操作時(shí),其vptr復(fù)制操作必須保證安全。

            8.   每一個(gè)編譯器對(duì)于虛擬繼承的承諾,都表示必須讓derived class object中的virtual base class subobject的位置在執(zhí)行期準(zhǔn)備妥當(dāng)。維護(hù)位置的完整性是編譯器的責(zé)任。

            2002-6-27

            2.3 程序轉(zhuǎn)化語(yǔ)意學(xué)
            1.   每一個(gè)明確的初始化操作都會(huì)有兩個(gè)必要的程序轉(zhuǎn)化階段:先重寫(xiě)每一個(gè)定義,剝除其中的初始化操作,然后安插class的copy constructor調(diào)用操作。

            2.   把一個(gè)class object當(dāng)作參數(shù)傳給一個(gè)函數(shù)或是作為一個(gè)函數(shù)的返回值,相當(dāng)于以下形式的初始化操作:

            X xx = arg; 其中xx代表形式參數(shù)或返回值,而arg代表真正的參數(shù)值。

            3.   函數(shù)定義如下:X bar(){X xx; return xx;},bar()的返回值通過(guò)一個(gè)雙階轉(zhuǎn)化從局部對(duì)象xx中拷貝出來(lái):

            ü          首先為bar添加一個(gè)額外參數(shù),類型是class object的一個(gè)reference,這個(gè)參數(shù)用來(lái)放置被拷貝構(gòu)建而得的返回值。

            ü          然后在return指令之前安插一個(gè)copy constructor調(diào)用操作,以便將欲傳回之object的內(nèi)容當(dāng)作上述新增參數(shù)的初值,同時(shí)重寫(xiě)函數(shù)使它不返回任何值。

            4.   Named Return Value(NRV)優(yōu)化如今被視為是標(biāo)準(zhǔn)C++編譯器的一個(gè)義不容辭的優(yōu)化操作,它的特點(diǎn)是直接操作新添加的額外參數(shù)。注意只有copy constructor的出現(xiàn)才會(huì)激活C++編譯器的NRV優(yōu)化!NRV優(yōu)化雖然極大地改善了效率,但還是飽受批評(píng):一是優(yōu)化由編譯器默默完成,而是否完成以及其完成程度完全透明;二是一旦函數(shù)變得比較復(fù)雜,優(yōu)化就變得較難施行;三是優(yōu)化由可能使程序產(chǎn)生錯(cuò)誤——有時(shí)并不是對(duì)稱地調(diào)用constructor和destructor,而是copy constructor未被調(diào)用!

            5.   在編譯器提供NRV優(yōu)化的前提下,如果可以預(yù)見(jiàn)class需要大量的memberwise初始化操作,比如以by value的方式傳回objects,那么提供一個(gè)explicit inline copy constructor的函數(shù)實(shí)體就非常合理。此種情況下,沒(méi)有必要同時(shí)提供explicit assignment operator定義。

            6.   copy constructor的應(yīng)用迫使編譯器多多少少對(duì)程序代碼作部分優(yōu)化,尤其是當(dāng)一個(gè)函數(shù)以by value的方式傳回一個(gè)class object,而該class有一個(gè)copy constructor(或定義或合成)時(shí),無(wú)論在函數(shù)的定義還是在使用上將導(dǎo)致深?yuàn)W的程序轉(zhuǎn)化。此外,編譯器將實(shí)施NRV優(yōu)化。

            7.   注意正確使用memset()和memcpy(),它們都只有在classes不含任何由編譯器產(chǎn)生的內(nèi)部members如vptr時(shí)才能有效運(yùn)行!

            2002-6-30

            2.4 成員初始化列表
            1.   當(dāng)寫(xiě)下一個(gè)constructor時(shí),就有機(jī)會(huì)設(shè)定class members的初值。不是經(jīng)由member initialization list,就是在constructor函數(shù)本身之內(nèi)。

            2.   下列情況,為了讓程序能被順利編譯,必須使用member initialization list:

            ü          初始化一個(gè)reference member時(shí);

            ü          初始化一個(gè)const member時(shí);

            ü          調(diào)用一個(gè)base class的constructor,而它擁有一組參數(shù)時(shí);

            ü          調(diào)用一個(gè)member class的constructor,而它擁有一組參數(shù)時(shí)。

            3.   編譯器會(huì)對(duì)initialization list一一處理并可能重新排序,以反映出members的聲明次序,它會(huì)安插一些代碼到constructor內(nèi),并置于任何explicit user code之前。

            4.   一個(gè)忠告:請(qǐng)使用“存在于constructor體內(nèi)的一個(gè)member”,而不是“存在于member initialization list中的一個(gè)member”,來(lái)為另一個(gè)member設(shè)定初值。

            2002-7-1

            Data語(yǔ)意學(xué)    The Semantics of Data
            討論如下繼承體系:

                     class X{};

                     class Y : public virtual X{};

                     class Z : public virtual X{};

                     class A: public Y, public Z{};

            1.   一個(gè)empty class如class X{},它有一個(gè)隱晦的1 byte,那是被編譯器安插進(jìn)去的一個(gè)char,使得這個(gè)class的兩個(gè)objects得以在內(nèi)存中配置獨(dú)一無(wú)二的地址。

            2.    Y和Z的大小受到三個(gè)因素的影響:

            ü          語(yǔ)言本身所造成的額外負(fù)擔(dān)overhead。語(yǔ)言支持virtual base classes時(shí)導(dǎo)致的額外負(fù)擔(dān)反映在某種形式的指針身上,它要么指向virtual base class subobject,要么指向一個(gè)存放virtual base class subobject地址或者其偏移量offset的表格。

            ü          編譯器對(duì)于特殊情況所提供的優(yōu)化處理。virtual base class X 1 byte大小的subobject也出現(xiàn)在class Y和Z身上。傳統(tǒng)上它被放在derived class的固定部分的尾端。某些編譯器對(duì)empty virtual base提供特殊處理,將它視為derived class object最開(kāi)頭的一部分,它不用會(huì)任何的額外空間,也就是前面提到的1 byte。

            ü          Alignment的限制。Alignment就是將數(shù)值調(diào)整到某數(shù)的整數(shù)倍,在32位計(jì)算機(jī)上,通常該數(shù)為4 bytes(32位),以使bus的運(yùn)輸量達(dá)到最高效率。

            3.   一個(gè)virtual base class subobject只會(huì)在derived class中存在一份實(shí)體,不管它在class繼承體系中出現(xiàn)了多少次,class A的大小由下列幾點(diǎn)決定:

            ü              被大家共享的唯一一個(gè)class X實(shí)體,大小為1 byte;

            ü              Base Y、Z的大小減去因virual base class而配置的大小;

            ü              class A自己的大小;

            ü              class A的alignment數(shù)量。

            4.   C++ standard并不強(qiáng)制規(guī)定base class subobjects、不同存取級(jí)別的data members的排列次序這種瑣碎細(xì)節(jié),它也不規(guī)定virtual function以及virtual base classes的實(shí)現(xiàn)細(xì)節(jié)。

            5.   C++對(duì)象模型盡量以空間優(yōu)化和存取速度優(yōu)化來(lái)表現(xiàn)nonstatic data members,并且保持和C語(yǔ)言struct數(shù)據(jù)配置的兼容性。它把數(shù)據(jù)直接存放在每一個(gè)class object中,對(duì)于繼承而來(lái)的nonstatic data members,不管是virtual或nonvirtual base class也是如此。至于static data members則被放置在程序的一個(gè)global data segment中,不會(huì)影響個(gè)別class object的大小。static data member永遠(yuǎn)只存在一份實(shí)體,但是一個(gè)template class的static data member的行為稍有不同。

            3.1 Data Member的綁定
            inline member function軀體內(nèi)的data member綁定操作,會(huì)在整個(gè)class聲明完成后才發(fā)生,而argument list中的名稱還是會(huì)在它們第一次遭遇時(shí)被適當(dāng)?shù)貨Q議resolved完成。基于這種狀況,請(qǐng)始終把nested type聲明放在class的起始處。

                                                                                                                            2002-7-2

            3.2 Data Member的布局
            1.   每一個(gè)private、protected、public區(qū)段就是一個(gè)access section。C++ Standard要求,在同一個(gè)access section中,members的排列只需滿足“較晚出現(xiàn)的members在class object中有較高的地址”這一條件即可。也就是說(shuō)各個(gè)members并不一定的連續(xù)排列,alignment可能需要的bytes以及編譯器可能合成供內(nèi)部使用的data members都可能介于被聲明的members之間。

            2.   C++ Standard也允許編譯器將多個(gè)access sections之中的data members自由排列,不必在乎它們出現(xiàn)在class聲明中的次序。當(dāng)前各家編譯器都是把一個(gè)以上的access sections連鎖在一起,依照聲明的次序成為一個(gè)連續(xù)區(qū)塊。access sections的多寡不會(huì)導(dǎo)致額外負(fù)擔(dān)。

            3.   vptr傳統(tǒng)上會(huì)被放在所有明確聲明的members的最后,不過(guò)如今也有一些編譯器把vptr放在class object的最前端。

            4.   一個(gè)用來(lái)判斷哪一個(gè)section先出現(xiàn)的template function:

            template <class class_type, class data_type1, class data_type2>

            char* access_order(data_type1 class_type::*mem1,     data_type2 class_type::*mem2)

            {

                       assert(mem1 != mem2);

                       return mem1 < mem2 ? “member 1 occurs first” : “member 2 occurs first”;

            }


            本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/xjtuse_mal/archive/2007/03/01/1517806.aspx

            posted on 2010-10-14 10:13 Vincent 閱讀(370) 評(píng)論(0)  編輯 收藏 引用


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


            久久夜色精品国产亚洲| 久久这里有精品| 人妻中文久久久久| 2021国内精品久久久久久影院| 模特私拍国产精品久久| 久久久久亚洲AV成人片| 久久久久久久久久久免费精品 | 中文字幕久久波多野结衣av| 久久精品亚洲精品国产色婷| 久久久久香蕉视频| 奇米综合四色77777久久| 一本久久a久久精品综合夜夜| 久久精品中文无码资源站| 欧美精品一区二区精品久久| 综合久久给合久久狠狠狠97色 | 久久精品国产99久久香蕉| 久久夜色精品国产噜噜麻豆| 亚洲精品乱码久久久久久蜜桃| 久久精品免费观看| 久久精品中文闷骚内射| 中文字幕久久亚洲一区| 91精品观看91久久久久久| 91精品国产综合久久婷婷| 无码精品久久久久久人妻中字| 91麻豆国产精品91久久久| 欧美成a人片免费看久久| 久久99精品国产99久久6男男| 无码人妻久久一区二区三区| 久久午夜福利无码1000合集| 性做久久久久久免费观看| 久久一区二区三区99| 久久无码一区二区三区少妇| 精品久久久无码中文字幕天天| 久久这里只精品国产99热| 狠狠色丁香婷综合久久| 丰满少妇人妻久久久久久| 97久久香蕉国产线看观看| 色噜噜狠狠先锋影音久久| 国产成人99久久亚洲综合精品 | 国内精品久久久久影院日本| 久久人人爽爽爽人久久久|