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

洛譯小筑

別來無恙,我的老友…
隨筆 - 45, 文章 - 0, 評論 - 172, 引用 - 0
數(shù)據(jù)加載中……

[ECPP讀書筆記 條目31] 盡量減少文件間的編譯依賴

在你的開發(fā)工作中,你可能需要對于某個類的具體實現(xiàn)做出一個細小的修改。提醒你一下,修改的地方不是類接口,而是實現(xiàn)本身,并且僅僅是私有部分。完成之后,你開始對程序進行重新構建,這時你肯定會認為這一過程將十分短暫,畢竟你只對一個類做出了修改。當你按下“構建”按鈕,或輸入make命令(或者其他什么等價的操作)之后,你驚呆了,然后你臉上便呈現(xiàn)出一個大大的囧字,因為你發(fā)現(xiàn)整個世界都重新編譯并重新鏈接了!真是人神共憤!

問題的癥結在于:C++并不擅長區(qū)分接口和實現(xiàn)。一個類的定義不僅指定了類接口的內(nèi)容,而且指明了相當數(shù)量的實現(xiàn)細節(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)所使用的類(即stringDateAddress)定義,那么Person類將不能夠得到編譯。通常這些定義通過#include指令來提供,因此在定義Person類的文件中,你應該能夠找到這樣的內(nèi)容:

#include <string>

#include "date.h"

#include "address.h"

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

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

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的客戶來說,僅在類接口有改動時,才需要進行重新編譯。

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

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

int main()

{

 int x;                            // 定義一個int

 

 Person p( 參數(shù) );                  // 定義一個Person

   ...

}

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

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

int main()

{

  int x;                           // 定義一個int

 

  Person *p;                       // 定義一個Person

  ...

}

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

#include <string>          // 標準庫成員,不允許對其進行前置聲明

#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;

};                         // 關于std::tr1::shared_ptr的更多信息

                           // 參見條目13

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

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

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

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

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

class Date;                        // 類聲明

 

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

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

當然,傳值方式在通常情況下都不會是優(yōu)秀的方案(參見條目20),但是如果你出于某種原因使用了傳值方式時,此時必將引入不必要的編譯依賴,你依然難擇其咎。

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

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

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

 

Date today();                  // 同上

void clearAppointments(Date d);

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

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

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

諸如Person此類使用pimpl慣用法的類通常稱為句柄類。為了避免你對這樣的類如何工作產(chǎn)生疑問,一個途徑就是將類中所有的函數(shù)調(diào)用放在相關的具體實現(xiàn)類之前,并且讓這些具體實現(xiàn)類去做真實的工作。請看下面的示例,其中演示了Person的成員函數(shù)應該如何實現(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的構造函數(shù)是如何調(diào)用PersonImpl的構造函數(shù)的(通過使用new - 參見條目16),以及Person::name是如何調(diào)用PersonImpl::name的。這兩點很重要。將Person定制為一個句柄類并不會改變它所做的事情,而是僅僅改變它做事情的方式。

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

接口類與Java和.NET中的接口一脈相承,但是C++并沒有像Java和.NET中那樣對接口做出非常嚴格的限定。比如說,無論是Java還是.NET都不允許接口中出現(xiàn)數(shù)據(jù)成員或者函數(shù)實現(xiàn),但是C++對這些都沒有做出限定。C++擁有更強靈活性是有實用價值的。就像條目36中所解釋的那樣,由于非虛函數(shù)的具體實現(xiàn)對于同一層次中所有的類都應該保持一致,因此不妨將這些函數(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的類卻是可行的——參見下文。)就像句柄類的客戶一樣,接口類客戶除非遇到接口類的接口有改動的情況,其他任何情況都不需要對代碼進行重新編譯。

接口類的客戶必須有一個創(chuàng)建新對象的手段。通常情況下,它們可以通過調(diào)用真正被實例化的派生類中的一個函數(shù)來實現(xiàn),這個函數(shù)扮演的角色就是派生類的構造函數(shù)。這樣的函數(shù)通常被稱作工廠函數(shù)(參見條目13)或者虛構造函數(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();

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

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

當然,與此同時,必須要對支持某一接口類的接口的具體類做出定義,并且必須有真實的構造函數(shù)得到調(diào)用。比如說,有一個具體的派生類RealPerson使用了接口類Person,這一派生類應為其繼承而來的虛函數(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),它應能夠創(chuàng)建不同種類的派生類對象,創(chuàng)建的過程基于某些相關信息,例如:新加入的函數(shù)的參數(shù)值、從一個文件或數(shù)據(jù)庫中得到讀到的數(shù)值,環(huán)境變量,等等。

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

句柄類和接口類將接口從實現(xiàn)中分離開來,因此降低了文件間的編譯依賴。如果你喜歡吹毛求疵,那么你一定在等待我來添加一條注釋。“這么多變魔術般古怪的事情會帶來多大開銷?”這個問題的答案就是計算機科學中極為普遍的一個議題:你的程序在運行時更慢了一步,另外,每個對象所占的空間更大了一點。

使用句柄類的情況下,成員函數(shù)必須通過實現(xiàn)指針來取得對象的數(shù)據(jù)。這樣無形中增加了每次訪問時迂回的層數(shù)。同時,為保證每個對象都擁有足夠的內(nèi)存空間,你必須增大實現(xiàn)指針所指向的區(qū)域的內(nèi)存空間。最后,你必須要對實現(xiàn)指針進行初始化(在句柄類的構造函數(shù)中),以便于將其指向一個動態(tài)分配的實現(xiàn)對象,這樣做將會招致動態(tài)內(nèi)存分配(以及由此產(chǎn)生的釋放)所帶來的固有的開銷,也有可能遭遇bad_alloc(內(nèi)存不足)異常。

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

最后,無論是句柄類還是接口類,都不適合于過多使用內(nèi)聯(lián)。條目30中解釋了為什么一般情況下要將內(nèi)聯(lián)的函數(shù)體放置在頭文件中,然而句柄和接口類都是特別設計用來隱藏諸如函數(shù)體等具體實現(xiàn)內(nèi)容的。

然而,對于句柄類和接口類來說,僅僅由于它們會帶來一些額外的開銷就遠離它們,也是一個嚴重的錯誤。你并不會因為虛函數(shù)存在缺點放棄使用它,不是嗎?(如果你真的想放棄,那么你可能看錯書了。)你應該以一個進化演進的方式來使用這些技術。在開發(fā)過程中,嘗試使用句柄類和接口類來減少改動具體實現(xiàn)時為客戶帶來的影響。在生產(chǎn)環(huán)境中,如果應用這些技術導致程序的速度和/或大小的變動足夠顯著,從而沖淡了不同的類之間所增加關系度的影響,應適時使用具體的類來取代句柄類和接口類。

時刻牢記

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

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

 

posted on 2008-01-01 01:37 ★ROY★ 閱讀(2179) 評論(7)  編輯 收藏 引用 所屬分類: Effective C++

評論

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴  回復  更多評論   

好東東啊,以前咋就沒有看到呢?
2008-01-02 09:01 | FongLuo

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴  回復  更多評論   

不好的地方是,會造成大量的代碼重復...
反復敲這些代碼也很麻煩.
另外:
如果用引用,則對構造形式要求教高.從而要求類有高度的面向?qū)ο筇匦?
如果用指針,又感覺不是很徹底面向?qū)ο?需要對資源進行管理.以及有效性判斷等.
2008-01-02 18:49 | zwp

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴  回復  更多評論   

贊同zwp的觀點,一個類變成了兩個類,既影響了程序的清晰性,又給實現(xiàn)帶來額外的工作
2008-01-02 21:31 | giscn

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴  回復  更多評論   

不知道不登錄能否回復,所以發(fā)了兩次。
這樣做使一個類變成了兩個類,既影響了程序的清晰性,又給實現(xiàn)帶來額外的工作,本質(zhì)上只是將一個問題變成了另外一個問題,當然某些場合出于封裝的目的,是可以采用這個方法。如果組織一下頭文件,減少不必要的引用,編譯速度還是很快的,記得96年的時候,一個30萬行的c++ 程序,在 cyrix 150 (老古董了,比奔騰133差) 全部編譯只要90s。花點時間組織一下頭文件比這個方式實用得多,當然如果你是做GUI, 用了BCG 或者 Xtreme, 上述方法估計也沒啥用了。
2008-01-02 21:50 | giscn

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴[未登錄]  回復  更多評論   

其他面向?qū)ο笳Z言中內(nèi)置的一些高級功能,
在C++中往往要手工實現(xiàn)。
這也許正是C++的魅力所在。

好比Ferrari430,永遠是手動擋的。。。
2008-01-04 22:35 | C++

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴  回復  更多評論   

這兩個東西在模式設計中都有介紹,但是作為封裝來講述的,而不是編譯來講述的:
模式設計中介紹的分別為Bridge模式和工廠模式(Factory和Abstract Factory)。
頭文件的編譯其實不然,從維護上講,上面的介紹是非常不錯的。另外具體的,一般英語用Concrete,用Real好像比較少見!
2008-01-07 13:18 | newrain

# re: 【讀書筆記】[Effective C++第3版][第31條] 要努力減少文件間的編譯依賴  回復  更多評論   

字兒總么弄么小呢?看不清,也看不懂!太深了,newbee!
2008-01-07 20:58 | vin
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美日韩成人一区| 美国成人直播| 亚洲美女av网站| 美日韩精品视频| 香蕉久久夜色| 亚洲图片在线观看| 91久久精品日日躁夜夜躁欧美| 国产欧美日韩专区发布| 欧美日韩精品一二三区| 久久精品一区二区三区不卡牛牛| 亚洲一区亚洲二区| 日韩午夜在线电影| 亚洲欧洲在线一区| 男女激情视频一区| 久久综合九九| 久久夜色精品国产欧美乱| 亚洲欧美在线磁力| 亚洲桃花岛网站| 在线中文字幕日韩| 日韩视频在线观看国产| 亚洲黄色性网站| ●精品国产综合乱码久久久久| 国产在线欧美| 国产午夜亚洲精品羞羞网站| 国产精品性做久久久久久| 欧美图区在线视频| 欧美四级在线观看| 欧美日韩视频在线一区二区 | 亚洲素人在线| 日韩手机在线导航| 亚洲精品视频一区二区三区| 亚洲欧洲一区二区在线播放| 亚洲风情在线资源站| 欧美国产在线视频| 亚洲国产高潮在线观看| 亚洲国产欧美另类丝袜| 91久久久在线| 亚洲六月丁香色婷婷综合久久| 亚洲三级影片| 日韩午夜视频在线观看| 夜色激情一区二区| 亚洲一区二区三区777| 亚洲男女自偷自拍图片另类| 亚洲欧美日韩一区二区在线 | 久久成人精品电影| 欧美资源在线观看| 久久综合激情| 欧美电影在线观看| 欧美日韩综合另类| 国产精品美女久久久久aⅴ国产馆| 国产精品视频第一区| 国产亚洲福利社区一区| 在线欧美不卡| 99精品国产一区二区青青牛奶| 夜夜嗨av一区二区三区四区 | 欧美一级久久| 乱人伦精品视频在线观看| 欧美成va人片在线观看| 欧美精品综合| 国产精品毛片一区二区三区| 国内成人在线| 亚洲精品偷拍| 亚洲欧美日韩国产中文| 久久久久久噜噜噜久久久精品| 欧美电影免费观看高清完整版| 91久久综合亚洲鲁鲁五月天| 亚洲夜晚福利在线观看| 久久精品成人一区二区三区| 欧美成人自拍视频| 国产精品日本| 亚洲国产日韩欧美| 亚洲在线观看视频网站| 麻豆成人av| 99国产精品99久久久久久| 欧美一区二区三区免费视| 欧美成人免费网站| 国产精品视频第一区| 亚洲欧洲一区二区天堂久久| 午夜精品久久久久99热蜜桃导演| 男人插女人欧美| 在线一区观看| 美女精品国产| 国产日韩欧美亚洲| 一本久久综合亚洲鲁鲁| 久热精品视频在线观看一区| 99国产精品久久久久久久成人热| 久久久久国产精品一区二区| 欧美三级精品| 亚洲国产日韩一区二区| 欧美一区二区三区免费看| 亚洲国产精品一区二区三区| 欧美一区二区三区在线视频| 欧美日韩91| 亚洲国产一区二区a毛片| 欧美一级播放| 一区二区三区精品国产| 欧美大片在线观看一区| 国产在线一区二区三区四区| 亚洲自拍偷拍一区| 亚洲欧洲精品一区| 久久中文字幕导航| 国产视频亚洲精品| 亚洲一区二区三区激情| 91久久精品日日躁夜夜躁欧美| 欧美在线免费视频| 国产精品欧美日韩| 亚洲午夜激情网页| 亚洲精品久久久久久久久| 久久婷婷av| 黄色亚洲精品| 久久久99爱| 亚洲欧美视频一区二区三区| 欧美亚州在线观看| 亚洲色图制服丝袜| 亚洲精品久久久久| 欧美精品成人在线| 亚洲美女精品久久| 亚洲国产高清一区二区三区| 久久美女性网| 在线精品国精品国产尤物884a| 久久久伊人欧美| 欧美在线免费看| 国产综合色精品一区二区三区| 欧美在线|欧美| 亚洲一区在线观看免费观看电影高清| 欧美视频精品一区| 亚洲图片欧美午夜| 在线亚洲美日韩| 欧美亚州韩日在线看免费版国语版| 一本色道久久| 99精品黄色片免费大全| 欧美视频免费| 午夜精品久久久久久| 亚洲女ⅴideoshd黑人| 国产欧美午夜| 久久理论片午夜琪琪电影网| 久久国产精品久久精品国产| 在线播放亚洲| 亚洲成色www久久网站| 蜜桃精品一区二区三区| 亚洲精一区二区三区| 亚洲日本国产| 欧美视频一区二区| 香蕉久久精品日日躁夜夜躁| 欧美一区二区私人影院日本| 在线精品亚洲| 亚洲国产日韩美| 国产精品jizz在线观看美国| 欧美一区午夜精品| 久久国内精品视频| 亚洲黄一区二区| 日韩亚洲欧美在线观看| 国产精品视频xxx| 久久久久成人精品| 麻豆国产精品一区二区三区 | 欧美高清自拍一区| 在线综合欧美| 欧美亚洲一区二区在线| 亚洲国产成人久久综合一区| 91久久精品一区二区别| 国产精品久久久久久影视| 久久影音先锋| 欧美噜噜久久久xxx| 午夜精品网站| 玖玖玖国产精品| 亚洲深夜福利在线| 久久精品国产欧美亚洲人人爽| 亚洲人成人一区二区在线观看| 一区二区欧美激情| 国产一区二区在线观看免费播放| 欧美韩日高清| 国产精品爽爽ⅴa在线观看| 免费短视频成人日韩| 欧美视频在线观看一区| 久久免费黄色| 欧美视频二区| 免费成人高清在线视频| 欧美午夜电影在线观看| 欧美77777| 国产精品毛片一区二区三区| 欧美国产日韩一区二区三区| 国产精品欧美日韩久久| 亚洲电影免费在线| 国产三区精品| 亚洲精品视频在线观看网站| 韩国欧美国产1区| 日韩网站在线观看| 亚洲第一福利在线观看| 亚洲中字黄色| 99精品福利视频| 久久久久免费| 欧美在线视频一区二区| 欧美激情欧美激情在线五月| 久久人人97超碰精品888| 欧美三级视频在线播放| 亚洲二区视频| 1024亚洲| 欧美在线视频a| 小嫩嫩精品导航| 欧美日韩免费在线|