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

Shuffy

不斷的學(xué)習(xí),不斷的思考,才能不斷的進(jìn)步.Let's do better together!
posts - 102, comments - 43, trackbacks - 0, articles - 19
【轉(zhuǎn)】http://m.shnenglu.com/tiandejian/archive/2008/01/01/ec_31.html

第31條:     要努力減少文件間的編譯依賴

為了更新某個類的某個功能實現(xiàn),你可能需要在浩瀚 C++ 的代碼中做出一個細(xì)小的修改,要提醒你的是,修改的地方不是類接口,而是實現(xiàn)本身,并且僅僅是私有成員。完成修改之后,你需要對程序進(jìn)行重新構(gòu)建,這時你肯定會認(rèn)為這一過程將十分短暫,畢竟你只對一個類做出了修改。當(dāng)你按下“構(gòu)建”按鈕,或輸入 make 命令(或者其他什么等價的操作)之后,你驚呆了,然后你就會陷入困惑中,因為你發(fā)現(xiàn)一切代碼都重新編譯并重新鏈接了!所發(fā)生的事情難道不會讓你感到不快嗎?

問題的癥結(jié)在于: C++ 并不擅長區(qū)分接口和實現(xiàn)。一個類的定義不僅指定了類接口的內(nèi)容,而且指明了相當(dāng)數(shù)量的實現(xiàn)細(xì)節(jié)。請看下面的示例:

class Person {

public:

 Person(const std::string& name, const Date& birthday,

         const Address& addr);

 std::string name() const;

 std::string birthDate() const;

 std::string address() const;

 ...

 

private:

      std::string theName;        // 具體實現(xiàn)

      Date theBirthDate;          // 具體實現(xiàn)

      Address theAddress;         // 具體實現(xiàn)

};

這里,如果無法訪問 Person 具體實現(xiàn)所使用的類(也就是 string Date Address )定義,那么 Person 類將不能夠得到編譯。通常這些定義通過 #include 指令來提供,因此在定義 Person 類的文件中,你應(yīng)該能夠找到這樣的內(nèi)容:

#include <string>

#include "date.h"

#include "address.h"

不幸的是,這樣做使得定義 Person 的文件對這些頭文件產(chǎn)生了依賴。如果任一個頭文件的內(nèi)容被修改了,或者這些頭文件所依賴的另外某個頭文件被修改,那么包含 Person 類的文件就必須重新編譯,有多少個文件包含 Person ,就要進(jìn)行多少次編譯操作。這種瀑布式的編譯依賴將招致無法估量的災(zāi)難式的后果。

你可能會考慮:為什么 C++ 堅持要將類具體實現(xiàn)的細(xì)節(jié)放在類定義中呢?假如說,如果我們換一種方式定義 Person ,單獨(dú)編寫類的具體實現(xiàn),結(jié)果又會怎樣呢?

namespace std {

     class string;               // 前置聲明 ( 這個是非法的,參見下文 )

}

 

class Date;                     // 前置聲明

class Address;                  // 前置聲明

 

class Person {

public:

      Person(const std::string& name, const Date& birthday,

                 const Address& addr);

      std::string name() const;

      std::string birthDate() const;

      std::string address() const;

    ...

};

如果這樣可行,那么對于 Person 的客戶端程序員來說,僅在類接口有改動時,才需要進(jìn)行重新編譯。

這種想法存在著兩個問題。首先, string 不是一個類,它是一個 typedef typedef basic_string<char> string )。于是,針對 string 的前置聲明就是非法的。實際上恰當(dāng)?shù)那爸寐暶饕獜?fù)雜的多,因為它涉及到其他的模板。然而這不是主要問題,因為你本來就不應(yīng)該嘗試手工聲明標(biāo)準(zhǔn)庫的內(nèi)容。僅僅使用恰當(dāng)?shù)?/span> #include 指令就可以了。標(biāo)準(zhǔn)頭文件一般都不會成為編譯中的瓶頸,尤其是在你的編譯環(huán)境允許你利用事先編譯好的頭文件時更為突出。如果分析標(biāo)準(zhǔn)頭文件對你來說的確是件麻煩事,那么你可能就需要改變你的接口設(shè)計,避免去使用那些會帶來多余 #include 指令的標(biāo)準(zhǔn)類成員。

對所有的類做前置聲明會遇到的第二個(同時也是更顯著的)難題是:在編譯過程中,編譯器需要知道對象的大小。請觀察下面的代碼:

int main()

{

  int x;                          // 定義一個 int

 

  Person p( params );             // 定義一個 Person

   ...

}

當(dāng)編譯器看到了 x 的定義時,它們就知道該為其分配足夠的內(nèi)存空間(通常位于棧中)以保存一個 int 值。這里沒有問題。每一種編譯器都知道 int 的大小。當(dāng)編譯器看到 p 的定義時,他們知道該為其分配足夠的空間以容納一個 Person ,但是他們又如何得知 Person 對象的大小呢?得到這一信息的唯一途徑就是通過類定義,但是如果允許類定義省略具體實現(xiàn)的細(xì)節(jié),那么編譯器又如何得知需要分配多大空間呢?

同樣的問題不會在 Smalltalk Java 中出現(xiàn),因為在這些語言中,每當(dāng)定義一個對象時,編譯器僅僅分配指向該對象指針大小的空間。也就是說,在這些語言中,上面的代碼將做如下的處理:

int main()

{

 int x;                         // 定義一個 int

 

 Person *p;                     // 定義一個 Person

 ...

}

當(dāng)然,這段代碼在 C++ 中是合法的,于是你可以自己通過“將對象實現(xiàn)隱藏在指針之后”來玩轉(zhuǎn)前置聲明。對于 Person 而言,實現(xiàn)方法之一就是將其分別放在兩個類中,一個只提供接口,另一個存放接口對應(yīng)的具體實現(xiàn)。暫且將具體實現(xiàn)類命名為 PersonImpl Person 類的定義應(yīng)該是這樣的:

#include <string>                // 標(biāo)準(zhǔn)庫成員,不允許對其進(jìn)行前置聲明

 

#include <memory>               // 為使用 tr1::shared_ptr; 稍后介紹

 

class PersonImpl;               // Person 實現(xiàn)類的前置聲明

 

class Date;                     // Person 接口中使用的類的前置聲明

class Address;

 

class Person {

public:

 Person(const std::string& name, const Date& birthday,

        const Address& addr);

 std::string name() const;

 std::string birthDate() const;

 std::string address() const;

 ...

 

private:                        // 指向?qū)崿F(xiàn)的指針

 std::tr1::shared_ptr<PersonImpl> pImpl;

};                // 關(guān)于 std::tr1::shared_ptr 的更多信息,參見 13

在這里,主要的類( Person )僅僅包括一個數(shù)據(jù)成員——一個指向其實現(xiàn)類( PersonImpl )的指針(這里是一個 tr1::shared_ptr ,參見第 13 條),其他什么也沒有。我們通常將這樣的設(shè)計稱為 pimpl idiom (指向?qū)崿F(xiàn)的指針)。在這樣的類中,指針名通常為 pImpl ,就像上面代碼中一樣。

通過這樣的設(shè)計, Person 的客戶端程序員將會與日期、地址和人這些信息隔離開。你可以隨時修改這些類的具體實現(xiàn),但是 Person 的客戶端程序員不需要重新編譯。另外,由于客戶端程序員無法得知 Person 的具體實現(xiàn)細(xì)節(jié),他們就不容易編寫出依賴于這些細(xì)節(jié)的代碼。這樣做真正起到了分離接口和實現(xiàn)的目的。

這項分離工作的關(guān)鍵所在,就是用聲明的依賴來取代定義的依賴。這就是最小化編譯依賴的核心所在:只要可行,就要將頭文件設(shè)計成自給自足的,如果不可行,那么就依賴于其他文件中的聲明語句,而不是定義。其他一切事情都應(yīng)遵從這一基本策略。于是有:

只要使用對象的引用或指針可行時,就不要使用對象。 只要簡單地通過類型聲明,你就可以定義出類型的引用和指針。反觀定義類型對象的情形,你就必須要進(jìn)行類型定義了。

只要可行,就用類聲明依賴的方式取代類定義依賴。 請注意你在使用一個類時,如果你需要聲明一個函數(shù),那么在任何情況下定義出這個類都不是必須的。即使這個函數(shù)以傳值方式傳遞或返回這個類的對象:

class Date;                     // 類聲明

 

Date today();                   // 這樣是可行的

void clearAppointments(Date d);// 但并沒有必要對 Date 類做出定義

當(dāng)然,傳值方式在通常情況下都不會是優(yōu)秀的方案,但是如果你發(fā)現(xiàn)某些情景下不得不使用傳值方式時,就會引入不必要的編譯依賴,你依然難擇其咎。

在不定 Date 的具體實現(xiàn)的情況下,就可以聲明 today clearAppointments C++ 的這 一能力恐怕會讓你感到吃驚,但是實際上這一行為又沒有想象中那么古怪。如果代碼中任意一處調(diào)用了這些函數(shù),那 么在這次調(diào)用前的某處必須要對 Date 進(jìn)行 定義。此時你又有了新的疑問:為什么我們要聲明沒有人調(diào)用的函數(shù)呢 , 這不是多此一舉嗎?這一疑問的答案很簡單:這種函數(shù)并不是沒有人調(diào)用,而是不是所有人都會去調(diào)用。假設(shè)你的庫中包含許多函數(shù)聲明,這并不意味著每一位客戶端程序員都會使用到所有的函數(shù)。上文的做法中,提供類定義的職責(zé)將從頭文件中的函數(shù)聲明轉(zhuǎn)向客戶端文件中包含的函數(shù)調(diào)用,通過這一過程,你就排除了手工造成的客戶端類定義依賴,這些依賴實際上是多余的。

為聲明和定義分別提供頭文件。 為了進(jìn)一步貫徹上文中的思想,頭文件必須要一分為二:一個存放聲明,另一個存放定義。當(dāng)然這些文件必須保持相互協(xié)調(diào)。如果某處的一個聲明被修改了,那么相應(yīng)的定義處就必須做出相應(yīng)的修改。于是,庫的客戶端程序員就應(yīng)該始終使用 #include 指令 來包含一個聲明頭文件,而不是自己進(jìn)行前置聲明,類創(chuàng)建者應(yīng)提供兩個頭文件。比如說 ,在 Date 客戶端程序員需要聲明 today clearAppointments 時,就應(yīng)該無需向上文中那樣, Date 進(jìn) 行前置聲明。更好的方案是用 #include 指令來引入恰當(dāng)?shù)穆暶黝^文件:

#include "datefwd.h"        // 包含 Date 類聲明 ( 而不是定義 ) 的頭文件

 

Date today();              // 同上

void clearAppointments(Date d);

頭文件“ datefwd.h ”中僅包含聲明,這一名字來源于 C++ 標(biāo)準(zhǔn)庫中的 <iosfwd> (參見第 54 條)。 <iosfwd> 包含著 IO 流組件的聲明,這些 IO 流組件相應(yīng)的定義分別存放在不同的幾個頭文件中,包括: <sstream> <streambuf> <fstream> 以及 <iostream>

從另一個角度來講,使用 <iosfwd> 作示例也是頗有裨益的,因為它告訴我們本節(jié)中的建議不僅對非模板的類有效,而且對模板同樣適用。盡管在第 30 條中分析過,在許多構(gòu)建環(huán)境中,模板定義通常保存在頭文件中,一些構(gòu)建環(huán)境中還是允許將模板定義放置在非頭文件的代碼文件里,因此提供為模板提供僅包含聲明的頭文件并不是沒有意義的。 <iosfwd> 就是這樣一個頭文件。

C++ 提供了 export 關(guān)鍵字,它用于分離模板聲明和模板定義。但是遺憾的是,編譯器對 export 的支持是十分有限的,實際操作中 export 更似雞肋。因此在高效 C++ 編程中, export 究竟扮演什么角色,討論這個問題還為時尚早。

諸如 Person 此類使用 pimpl idiom 的類通常稱為句柄類。為了避免你對這樣的類如何完成這些工作產(chǎn)生疑問,一個途徑就是將類中所有的函數(shù)調(diào)用放在相關(guān)的具體實現(xiàn)類之前,并且讓這些具體實現(xiàn)類去做真實的工作。請看下面的示例,其中演示了 Person 的成員函數(shù)應(yīng)該如何實現(xiàn):

#include "Person.h"        // 我們將編寫 Person 類的具體實現(xiàn),

                           // 因此此處必須包含類定義。

 

#include "PersonImpl.h"    // 同時,此處必須包含 PersonImpl 的類定義,

                           // 否則我們將不能調(diào)用它的成員函數(shù);請注意,

                           // PersonImpl 擁有與 Person 完全一致的成員

                           // 函數(shù) - 也就是說,它們的接口是一致的。

 

Person::Person(const std::string& name, const Date& birthday,

               const Address& addr)

: pImpl(new PersonImpl(name, birthday, addr))

{}

 

std::string Person::name() const

{

 return pImpl->name();

}

請注 意下面兩個問題: Person 的構(gòu)造函數(shù)是如何調(diào)用 PersonImpl 的構(gòu)造函 數(shù)的(通過使 new - 參見第 16 條),以及 Person::name 是如何調(diào)用 PersonImpl :: name 的。這兩點(diǎn)很重要。將 Person 定制為一個句柄類并不會改變它所做的事情,這樣做僅僅改變它做事情的方式。

除了句柄類的方法,我們還可以采用一種稱為“接口類”的方法來講 Person 定制為特種的抽象基類。這種類的目的就是為派生類指定一個接口(參見第 34 條)。于是,通常情況下它沒有數(shù)據(jù)成員,沒有構(gòu)造函數(shù),但是擁有一個虛析構(gòu)函數(shù)(參見第 7 條),以及一組指定接口用的純虛函數(shù)。

接口類與 Java .NET 中的接口一脈相承,但是 C++ 并沒有像 Java .NET 中那樣對接口做出非常嚴(yán)格的限定。比如說,無論是 Java 還是 .NET 都不允許接口中出現(xiàn)數(shù)據(jù)成員或者函數(shù)實現(xiàn),但是 C++ 對這些都沒有做出限定。 C++ 所擁有的更強(qiáng)的機(jī)動靈活性是非常有用的。就像第 36 條中所解釋的那樣,由于非虛函數(shù)的具體實現(xiàn)對于同一層次中所有的類都應(yīng)該保持一致,因此不妨將這些函數(shù)實現(xiàn)放置在聲明它們的接口類中,這樣做是有意義的,

Person 的接口類可以是這樣的:

class Person {

public:

 virtual ~Person();

 

 virtual std::string name() const = 0;

 virtual std::string birthDate() const = 0;

 virtual std::string address() const = 0;

 ...

};

這個類的客戶端程序員必須要基于 Person 的指針和引用來編寫程序,因為實例化一個包含純虛函數(shù)的類是不可能的。(然而,實例化一個繼承自 Person 的類卻是可行的—參見下文。)就像句柄類的客戶端程序員一樣,接口類客戶端程序員除非遇到接口類的接口有改動的情況,其他任何情況都不需要對代碼進(jìn)行重新編譯。

接口類的客戶端程序員必須有一個創(chuàng)建新對象的手段。通常情況下,它們可以通過調(diào)用真正被實例化的派生類中的一個函數(shù)來實現(xiàn),這個函數(shù)扮演的角色就是派生類的構(gòu)造函數(shù)。這樣的函數(shù)通常被稱作工廠函數(shù)(參見第 13 條)或者虛構(gòu)造函數(shù)。這種函數(shù)返回一個指向動態(tài)分配對象的指針(最好是智能指針—參見第 18 條),這些動態(tài)分配的對象支持接口類的接口。這樣的函數(shù)通常位于接口類中,并且聲明為 static 的:

class Person {

public:

 ...

 

  static std::tr1::shared_ptr<Person>// 返回一個 tr1::shared_ptr

   create(const std::string& name,   // 它指向一個 Person 對象,這個

          const Date& birthday,       // Person 對象由給定的參數(shù)初始化,

          const Address& addr);       // 為什么返回智能指針參見第 18

 ...

};

客戶端程序員這樣使用:

std::string name;

Date dateOfBirth;

Address address;

...

 

// 創(chuàng)建一個支持 Person 接口的對象

std::tr1::shared_ptr<Person> pp(Person::create(name, dateOfBirth, address));

 

...

 

std::cout << pp->name()         // 通過 Person 的接口使用這一對象

          << " was born on "

           << pp->birthDate()

          << " and now lives at "

          << pp->address();

...                              // 當(dāng)程序執(zhí)行到 pp 的作用域之外時,

                                // 這一對象將被自動刪除—參見第 13

當(dāng)然,與此同時,必須要對支持接口類的接口的具體類進(jìn)行定義,并且必須有真實的構(gòu)造函數(shù)得到調(diào)用。比如說,接口類 Person 必須有一個具體的派生類 RealPerson ,它應(yīng)當(dāng)為其繼承而來的虛函數(shù)提供具體實現(xiàn):

class RealPerson: public Person {

public:

 RealPerson(const std::string& name, const Date& birthday,

             const Address& addr)

 : theName(name), theBirthDate(birthday), theAddress(addr)

 {}

 

 virtual ~RealPerson() {}

 

 std::string name() const;      // 這里省略了這些函數(shù)的具體實現(xiàn),

 std::string birthDate() const;// 但是很容易想象它們是什么樣子。

 std::string address() const;

 

private:

 std::string theName;

 Date theBirthDate;

 Address theAddress;

};

RealPerson ,編寫 Person::create 就如 探囊取物一般:

std::tr1::shared_ptr<Person> Person::create(const std::string& name,

                                            const Date& birthday,

                                            const Address& addr)

{

 return std::tr1::shared_ptr<Person>(new RealPerson(name, birthday,addr));

}

Person::create 還有可以以一個更加貼近現(xiàn)實的方法來實現(xiàn),它應(yīng)能夠創(chuàng)建不同種類的派生類對象,創(chuàng)建的過程基于某些相關(guān)信息,例如:新加入的函數(shù)的參數(shù)值、從一個文件或數(shù)據(jù)庫中得到讀到的數(shù)值,環(huán)境變量,等等。

RealPerson 向我們展示了實現(xiàn)接口類的兩種通用的實現(xiàn)機(jī)制之一:它的接口規(guī)范繼 承自接口 類( Person ,然后實現(xiàn)接口中的函數(shù)。第二種實現(xiàn)接口類的方法牽扯到多重繼承,那是第 40 條中探索的主題。

句柄類和接口類將接口從實現(xiàn)中分離開來,因此降低了文件間的編譯依賴。如果你是一個喜歡吹毛求疵的人,那么你一定又在想法挖苦本屆的思想了:“做了這么多變魔術(shù)般古怪的事情,我又能得到什么呢?”這個問題的答案就是計算機(jī)科學(xué)中極為普遍的一個議題:你的程序在運(yùn)行時更慢了一步,另外,每個對象所占的空間更大了一點(diǎn)。

使用句柄類的情況下,成員函數(shù)必須通過實現(xiàn)指針來取得對象的數(shù)據(jù)。這樣無形中增加了每次訪問時迂回的層數(shù)。同時,實現(xiàn)指針?biāo)赶虻膶ο笏嫉目臻g更大了一些,你必須要考慮這一問題。最后,你必須要對實現(xiàn)指針進(jìn)行初始化(在句柄類的構(gòu)造函數(shù)中),以便于將其指向一個動態(tài)分配的實現(xiàn)對象,于是你就必須自己承擔(dān)動態(tài)內(nèi)存分配(以及相關(guān)的釋放)內(nèi)在的開銷以及遭遇 bad_alloc (內(nèi)存越界)異常的可能性。

由于對于接口類來說每次函數(shù)調(diào)用都是虛擬的,因此你在每調(diào)用一次函數(shù)的過程中你就會為其付出一次間接跳轉(zhuǎn) 的代價(參見第 7 條)。同時,派生自接口類的對象必須包含一個虛 函數(shù)表指針(依然參見第 7 條)。這一指針也可能會使保存一個對象所需要的空間加大,這取決于接口類是否是該對象中虛函數(shù)的唯一來源。

最后,無論是句柄類還是接口類,都不適合于過多使用內(nèi)聯(lián)。句柄和接口類都是特別設(shè)計用來隱藏諸如函數(shù)體等具體實現(xiàn)內(nèi)容的。

然而,僅僅由于句柄類和接口類會帶來一些額外的開銷而遠(yuǎn)離它們,這樣的做法存在致命的錯誤。虛函數(shù)也一樣,你并不希望忽略這些問題,是嗎?(如果你真希望忽略些問題,那么你可能看錯書了。)你應(yīng)該把使用這些技術(shù)看作一個革命性的手段。在開發(fā)過層中,使用句柄類和接口類,來減少在具體實現(xiàn)有改動時為客戶端程序員帶來的影響。在程序的速度和 / 或大小的變動太大,足以體現(xiàn)出類之間所增加的耦合度時,還是可以適時使用具體的類來取代句柄類和接口類。

銘記在心

最小化編譯依賴的基本理念就是使用聲明依賴代替定義依賴。基于這一理念有兩種實現(xiàn)方式,它們是:句柄類和接口類。

庫頭文件必須以完整、并且僅存在聲明的形式出現(xiàn)。無論是否涉及模板。

 

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            中文日韩电影网站| 久久尤物视频| 老司机午夜精品视频在线观看| 亚洲视频一区二区在线观看| 欧美日韩国产综合视频在线观看| 免费国产一区二区| 欧美va日韩va| 欧美成人精品高清在线播放| 欧美激情一区二区三区在线视频 | 欧美精品日韩三级| 欧美精品videossex性护士| 欧美电影免费观看大全| 欧美日韩精品综合| 国产美女诱惑一区二区| 狠狠色狠狠色综合日日91app| 在线国产亚洲欧美| 久久超碰97人人做人人爱| 久久人体大胆视频| 亚洲国产一区二区三区a毛片| 亚洲国产三级网| 一区二区欧美在线| 久久久欧美精品| 欧美日韩一区在线观看| 国产日韩欧美一区二区三区四区| 国模叶桐国产精品一区| 日韩一级免费观看| 欧美制服丝袜| 亚洲激情视频网| 久久国产精品色婷婷| 欧美日韩国产综合视频在线观看| 国产午夜精品一区二区三区视频| 亚洲经典在线看| 久久精品国产99国产精品澳门| 亚洲经典在线| 欧美在线免费视屏| 欧美日韩在线观看一区二区三区 | 欧美在线一级va免费观看| 久久亚洲综合| 一区二区三区www| 欧美va天堂va视频va在线| 国产麻豆精品视频| 99国产精品99久久久久久| 久久精品一本| 亚洲欧美日本日韩| 国产精品久久久久久久第一福利 | 久久久久国色av免费看影院 | 一本大道久久a久久精二百| 午夜日韩福利| 99riav久久精品riav| 久久夜色精品一区| 国产日韩欧美在线视频观看| 一区二区三区久久| 亚洲高清不卡一区| 免费日韩成人| 一区在线观看| 久久久久久高潮国产精品视| 这里只有精品电影| 国产精品国产三级欧美二区| 99视频精品免费观看| 亚洲福利精品| 欧美大片在线看| 日韩视频免费观看高清在线视频 | 亚洲欧美中文日韩在线| 国产精品区一区| 亚洲欧美一区二区视频| 一区二区三区日韩精品| 亚洲一区二区三区欧美| 亚洲日本一区二区三区| 欧美精品偷拍| 国产精品99久久久久久有的能看 | 国产视频一区在线| 欧美在线视频导航| 久久精品视频播放| 红杏aⅴ成人免费视频| 麻豆国产va免费精品高清在线| 久久久久久久999| 亚洲国产精品一区二区www在线| 欧美a级片一区| 欧美激情成人在线| 亚洲一区二区三区免费在线观看| 亚洲图片在线观看| 国模精品娜娜一二三区| 欧美福利视频在线观看| 欧美日本中文字幕| 午夜在线精品| 美日韩精品视频免费看| 中日韩男男gay无套| 亚洲欧美日韩视频一区| 黄色亚洲在线| 亚洲人成在线观看| 国产精品区一区二区三| 女女同性女同一区二区三区91| 欧美成ee人免费视频| 亚洲欧美另类久久久精品2019| 久久国产乱子精品免费女| 日韩视频二区| 欧美伊人精品成人久久综合97 | 亚洲人成人一区二区三区| 亚洲精品你懂的| 国产精品国产三级国产专区53| 久久一区欧美| 国产精品久久7| 最新国产の精品合集bt伙计| 国产麻豆午夜三级精品| 亚洲激情一区二区| 国内精品久久久久久| 在线视频精品| 亚洲久久在线| 久久这里只有| 久久av老司机精品网站导航| 欧美成人日本| 美女成人午夜| 国产欧美日韩视频一区二区| 亚洲日本电影| 樱花yy私人影院亚洲| 亚洲一区免费| 亚洲视频一二区| 欧美精品大片| 欧美激情精品久久久久久久变态 | 欧美日韩国产在线一区| 牛夜精品久久久久久久99黑人 | 欧美高清视频在线观看| 亚洲淫性视频| 欧美日韩国产在线播放| 欧美国产视频日韩| 激情久久久久久久久久久久久久久久 | 欧美福利电影网| 久久久夜色精品亚洲| 国产精品一二三视频| 在线一区观看| 亚洲特色特黄| 欧美视频在线免费| 99国内精品久久久久久久软件| 亚洲人成人一区二区三区| 久久综合伊人77777| 欧美福利视频| 亚洲精品美女在线观看播放| 快射av在线播放一区| 毛片一区二区| 亚洲成人资源网| 美女亚洲精品| 亚洲伦理中文字幕| 亚洲午夜伦理| 国产欧美一级| 久久久夜色精品亚洲| 欧美国产精品人人做人人爱| 亚洲黄色小视频| 欧美激情一区二区三区蜜桃视频| 亚洲国产精品一区二区第四页av | 亚洲深夜福利| 国产精品久久久久av免费| 亚洲一区自拍| 玖玖国产精品视频| 亚洲精品你懂的| 欧美体内谢she精2性欧美| 亚洲视频欧美在线| 久久精品人人做人人综合| 伊人久久大香线蕉av超碰演员| 老司机亚洲精品| 99国产精品视频免费观看| 欧美一区永久视频免费观看| 国产一区二区三区免费观看| 美女视频一区免费观看| 亚洲免费精彩视频| 久久久久久久999精品视频| 亚洲国产另类久久久精品极度| 欧美理论视频| 欧美专区在线播放| 亚洲激情视频网| 欧美亚洲网站| 亚洲肉体裸体xxxx137| 国产精品露脸自拍| 另类天堂av| 亚洲欧美日韩国产精品| 欧美激情免费观看| 欧美在线视频播放| aa日韩免费精品视频一| 国产一区二区精品久久99| 老司机久久99久久精品播放免费 | 欧美电影在线| 亚洲人成人一区二区三区| 嫩草国产精品入口| 在线一区视频| 亚洲电影免费观看高清完整版| 亚洲欧美韩国| 日韩视频―中文字幕| 国产一区导航| 国产精品久久久久毛片大屁完整版| 久久久国产精品亚洲一区| 亚洲深爱激情| 91久久精品美女高潮| 久久综合中文| 欧美一区二区三区四区在线观看地址| 亚洲人体一区| 在线欧美视频| 韩国欧美一区| 国产午夜精品一区理论片飘花| 国产精品xxx在线观看www| 欧美国产日韩xxxxx| 巨胸喷奶水www久久久免费动漫|