久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

《C++ Primer 5th》笔记(7 / 19):类

發布時間:2023/12/13 c/c++ 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《C++ Primer 5th》笔记(7 / 19):类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 定義抽象數據類型
      • 設計Sales_data類
        • 關鍵概念:不同的編程角色
        • 使用改進的Sales_data類
      • 定義改進的Sales_data類
        • 定義成員函數
        • 引入this
        • 引入const成員函數
        • 類作用域和成員函數
        • 在類的外部定義成員函數
        • 定義一個返回this對象的函數
      • 定義類相關的非成員函數
        • 定義read和print函數
        • 定義add函數
      • 構造函數
        • 合成的默認構造函數
        • 某些類不能依賴于合成的默認構造函數
        • 定義Sales_data的構造函數
        • = default的含義
        • 構造函數初始化列表
        • 在類的外部定義構造函數
      • 拷貝、賦值和析構
        • 某些類不能依賴于合成的版本
    • 訪問控制與封裝
      • 使用class或struct關鍵字
      • 友元
        • 關鍵概念:封裝的益處
        • 友元的聲明
    • 類的其他特性
      • 類成員再探
        • 定義一個類型成員
        • Screen類的成員函數
        • 令成員作為內聯函數
        • 重載成員函數
        • 可變數據成員
        • 類數據成員的初始值
      • 返回*this的成員函數
        • 從const成員函數返回*this,它的返回類型將是常量引用
        • 基于const的重載
        • 建議:對于公共代碼使用私有功能函數
      • 類類型
        • 類的聲明(可先聲明,暫時不定義)
      • 友元再探
        • 類之間的友元關系
        • 令成員函數作為友元
        • 函數重載和友元
        • 友元聲明和作用域
    • 類的作用域
      • 作用域和定義在類外部的成員
      • 名字查找與類的作用域
        • 用于類成員聲明的名字查找
        • 類型名要特殊處理
        • 成員定義中的普通塊作用域的名字查找
        • 類作用域之后,在外圍得作用域中查找
        • 在文件中名字得出現處對其進行解析
    • 構造函數再探
      • 構造函數初始值列表
        • 構造函數的初始值有時必不可少
        • 建議:使用構造函數初始值
        • 成員初始化的順序
        • 默認實參和構造函數
      • 委托構造函數
      • 默認構造函數的作用
        • 使用默認構造函數
      • 隱式的類類型轉換
        • 只允許一步類類型轉換
        • 類類型轉換不是總有效
        • explicit抑制構造函數定義的隱式轉換
        • explicit構造函數只能用于直接初始化,不能用于拷貝初始化
        • 為轉換顯示地使用構造函數(可忽視explicit)
        • 標準庫中含有顯式構造函數的類
      • 聚合類
      • 字面值常量類
        • constexpr構造函數
    • 類的靜態成員
      • 聲明靜態成員
        • 使用類的靜態成員
        • 定義靜態成員
        • 靜態成員的類內初始化
        • 靜態成員能用于某些場景,而普通成員不能
    • 一些術語

類的基本思想是數據抽象(data abstraction)和封裝(encapsulation)。數據抽象是一種依賴于接口( interface)和實現( implementation)分離的編程(以及設計)技術。類的接口包括用戶所能執行的操作;類的實現則包括類的數據成員、負責接口實現的函數體以及定義類所需的各種私有函數。

封裝實現了類的接口實現的分離。封裝后的類隱藏了它的實現細節,也就是說,類的用戶只能使用接口而無法訪問實現部分。

類要想實現數據抽象和封裝,需要首先定義一個抽象數據類型(abstract data type)。在抽象數據類型中,

  • 由類的設計者負責考慮類的實現過程;
  • 使用該類的程序員則只需要抽象地思考類型做了什么,而無須了解類型的工作細節。

定義抽象數據類型

在第1章中使用的Sales_item類是一個抽象數據類型,我們通過它的接口來使用一個Sales_item對象。我們不能訪問Sales_item對象的數據成員,事實上,我們甚至根本不知道這個類有哪些數據成員。

與之相反,第2章Sales_data類不是一個抽象數據類型。它允許類的用戶直接訪問它的數據成員,并且要求由用戶來編寫操作。

要想把Sales_data變成抽象數據類型,我們需要定義一些操作以供類的用戶使用。一旦 Sales_data定義了它自己的操作,我們就可以封裝(隱藏)它的數據成員了。

設計Sales_data類

我們的最終目的是令Sales_data支持與Sales_item類完全一樣的操作集合。Sales_item類有一個名為isbn的成員函數(member function),并且支持+、=、+=、<<和>>運算符。

我們將在第14章學習如何自定義運算符?,F在,我們先為這些運算定義普通(命名的)函數形式。

綜上所述,Sales_data的接口應該包含以下操作:

  • 一個isbn 成員函數,用于返回對象的ISBN編號
  • 一個combine 成員函數,用于將一個Sales_data對象加到另一個對象上
  • 一個名為 add 的函數,執行兩個Sales_data對象的加法
  • 一個read函數,將數據從istream讀入到Sales_data對象中
  • 一個print函數,將Sales_data對象的值輸出到ostream

關鍵概念:不同的編程角色

程序員們常把運行其程序的人稱作用戶(user)。類似的,類的設計者也是為其用戶設計并實現一個類的人;顯然,類的用戶是程序員,而非應用程序的最終使用者。

當我們提及“用戶”一詞時,不同的語境決定了不同的含義。如果我們說用戶代碼或者Sales data類的用戶,指的是使用類的程序員;如果我們說書店應用程序的用戶,則意指運行該應用程序的書店經理。

Note:C++程序員們無須刻意區分應用程序的用戶以及類的用戶。

在一些簡單的應用程序中,類的用戶和類的設計者常常是同一個人。盡管如此,還是最好把角色區分開來。當我們設計類的接口時,應該考慮如何才能使得類易于使用;而當我們使用類時,不應該顧及類的實現機理。

要想開發一款成功的應用程序,其作者必須充分了解并實現用戶的需求。同樣,優秀的類設計者也應該密切關注那些有可能使用該類的程序員的需求。作為一個設計良好的類,既要有直觀且易于使用的接口,也必須具備高效的實現過程。

使用改進的Sales_data類

在考慮如何實現我們的類之前,首先來看看應該如何使用上面這些接口函數。

舉個例子,我們使用這些函數編寫第一章店程序的另外一個版本,其中不再使用Sales_item對象,而是使用Sales_data對象:

Sales_data total; // variable to hold the running sum if (read(cin, total)) { // read the first transactionSales_data trans; // variable to hold data for the next transactionwhile(read(cin, trans)) { // read the remaining transactionsif (total.isbn() == trans.isbn()) // check the isbnstotal.combine(trans); // update the running total else {print(cout, total) << endl; // print the resultstotal = trans; // process the next book}}print(cout, total) << endl; // print the last transaction } else { // there was no inputcerr << "No data?!" << endl; // notify the user }

定義改進的Sales_data類

struct Sales_data {// new members: operations on Sales_data objectsstd::string isbn() const { return bookNo; }Sales_data& combine(const Sales_data&);double avg_price() const;//計算平均價格// data members are unchanged from § 2.6.1 (p. 72)std::string bookNo;//ISBN編號unsigned units_sold = 0;//本書銷量double revenue = 0.0;//總銷售收入 };// nonmember Sales_data interface functions Sales_data add(const Sales_data&, const Sales_data&); std::ostream &print(std::ostream&, const Sales_data&); std::istream &read(std::istream&, Sales_data&);

定義和聲明成員函數的方式與普通函數差不多。

成員函數的聲明必須在類的內部,它的定義則既可以在類的內部也可以在類的外部。

作為接口組成部分的非成員函數,例如 add、read和 print等,它們的定義和聲明都在類的外部。

Note:定義在類內部的函數是隱式的inline函數(第6章內容)。

定義成員函數

盡管所有成員都必須在類的內部聲明,但是成員函數體可以定義在類內也可以定義在類外。

對于Sales_data類來說,isbn函數定義在了類內,而combine和 avg_price定義在了類外。
我們首先介紹isbn函數,它的參數列表為空,返回值是一個string對象:

std::string isbn() const { return bookNo;}

和其他函數一樣,成員函數體也是一個塊。

關于 isbn函數一件有意思的事情是:它是如何獲得bookNo成員所依賴的對象的呢?

引入this

對isbn成員函數的調用:

total.isbn()

在這里,我們使用了點運算符來訪問total對象的isbn成員,然后調用它。

本章將介紹一種例外的形式,當我們調用成員函數時,實際上是在替某個對象調用它。如果isbn指向Sales_data的成員(例如 bookNo),則它隱式地指向調用該函數的對象的成員。在上面所示的調用中,當isbn返回 bookNo時,實際上它隱式地返回total.bookNo。

成員函數通過一個名為this的額外的隱式參數來訪問調用它的那個對象。當我們調用一個成員函數時,用請求該函數的對象地址初始化this。例如,如果調用

total.isbn()

則編譯器負責把total的地址傳遞給isbn的隱式形參this,可以等價地認為編譯器將該調用重寫成了如下的形式:

//偽代碼,用于說明調用成員函數的實際執行過程 Sales_data::isbn(&total)

其中,調用Sales_data的isbn成員時傳入了total的地址。

在成員函數內部,我們可以直接使用調用該函數的對象的成員,而無須通過成員訪問運算符來做到這一點,因為this所指的正是這個對象。任何對類成員的直接訪問都被看作this的隱式引用,也就是說,當isbn使用bookNo時,它隱式地使用this 指向的成員,就像我們書寫了this->bookNo一樣。

對于我們來說,this形參是隱式定義的。實際上,任何自定義名為this 的參數或變量的行為都是非法的。我們可以在成員函數體內部使用this,因此盡管沒有必要,但我們還是能把isbn定義成如下的形式:

std::string isbn() const { return this->bookNo;}

因為this 的目的總是指向“這個”對象,所以 this 是一個常量指針(第2章內容),我們不允許改變this中保存的地址。

引入const成員函數

isbn函數的另一個關鍵之處是緊隨參數列表之后的 const關鍵字,這里,const的作用是修改隱式this指針的類型。

默認情況下,this的類型是指向類類型非常量版本的常量指針。例如在Sales_data成員函數中, this 的類型是Sales_data *const。

盡管this是隱式的,但它仍然需要遵循初始化規則,意味著(在默認情況下)我們不能把this綁定到一個常量對象上。這一情況也就使得我們不能在一個常量對象上調用普通的成員函數

(MyNote:const對象不能調用普通成員函數。)

如果isbn是一個普通函數而且this是一個普通的指針參數,則我們應該把this聲明成const Sales data *const。畢竟,在isbn 的函數體內不會改變this所指的對象,所以把this設置為指向常量的指針有助于提高函數的靈活性。(MyNote:這樣可以讓非常量對象 與 常量對象都可以調用。)

然而,this是隱式的并且不會出現在參數列表中,所以在哪兒將this聲明成指向常量的指針就成為我們必須面對的問題。C++語言的做法是允許把const關鍵字放在成員函數的參數列表之后,此時,緊跟在參數列表后面的const表示 this是一個指向常量的指針。像這樣使用const的成員函數被稱作常量成員函數(const member function)。

可以把isbn的函數體想象成如下的形式:

//偽代碼,說明隱式的this指針是如何使用的 //下面的代碼是非法的:因為我們不能顯式地定義自己的this指針 //謹記此處的this是一個指向常量的指針,因為isbn是一個常量成員 std::string Sales_data::isbn(const Sales_data *const this){ return this->isbn;}

因為this是指向常量的指針,所以常量成員函數不能改變調用它的對象的內容。在上例中,isbn可以讀取調用它的對象的數據成員,但是不能寫入新值。

Note:常量對象,以及常量對象的引用或指針都只能調用常量成員函數。(本節一語蔽之)

類作用域和成員函數

回憶之前我們所學的知識,類本身就是一個作用域。類的成員函數的定義嵌套在類的作用域之內,因此,isbn中用到的名字bookNo其實就是定義在Sales_data內的數據成員。

值得注意的是,即使 bookNo定義在isbn之后,isbn也還是能夠使用bookNo。

編譯器分兩步處理類:

  • 首先編譯成員的聲明,
  • 然后才輪到成員函數體(如果有的話)。
  • 因此,成員函數體可以隨意使用類中的其他成員而無須在意這些成員出現的次序。

    在類的外部定義成員函數

    像其他函數一樣,當我們在類的外部定義成員函數時,成員函數的定義必須與它的聲明匹配。也就是說,返回類型、參數列表和函數名都得與類內部的聲明保持一致。如果成員被聲明成常量成員函數,那么它的定義也必須在參數列表后明確指定const 屬性。同時,類外部定義的成員的名字必須包含它所屬的類名:

    double Sales_data::avg_price() const {if (units_sold)return revenue/units_sold;elsereturn 0; }

    函數名Sales_data::avg_price使用作用域運算符來說明如下的事實:我們定義了一個名為avg_price的函數,并且該函數被聲明在類Sales_data的作用域內。一旦編譯器看到這個函數名,就能理解剩余的代碼是位于類的作用域內的。因此,當avg_price使用revenue和 units_sold 時,實際上它隱式地使用了Sales_data的成員。

    定義一個返回this對象的函數

    函數combine的設計初衷類似于復合賦值運算符+=,調用該函數的對象代表的是賦值運算符左側的運算對象,右側運算對象則通過顯式的實參被傳入函數:

    Sales_data& Sales_data::combine(const Sales_data &rhs){units_sold += rhs.units_sold;//把rhs的成員加到this對象的成員上revenue +=rhs.revenue;return *this;//返回調用該函數的對象 }

    當我們的交易處理程序調用如下的函數時,

    total.combine (trans) ; //更新變量total當前的值

    total的地址被綁定到隱式的 this 參數上,而rhs 綁定到了trans 上。因此,當combine執行下面的語句時,

    units_sold += rhs.units_sold;//把rhs的成員添加到this對象的成員中

    效果等同于求total.units_sold和trans.unit_sold的和,然后把結果保存到total.units_sold中。

    該函數一個值得關注的部分是它的返回類型和返回語句。一般來說,當我們定義的函數類似于某個內置運算符時,應該令該函數的行為盡量模仿這個運算符。內置的賦值運算符把它的左側運算對象當成左值返回(,因此為了與它保持一致,combine函數必須返回引用類型。因為此時的左側運算對象是一個Sales_data的對象,所以返回類型應該是Sales_data&。

    如前所述,我們無須使用隱式的this指針訪問函數調用者的某個具體成員,而是需要把調用函數的對象當成一個整體來訪問:

    return *this;//返回調用該函數的對象

    其中,return語句解引用this指針以獲得執行該函數的對象,換句話說,上面的這個調用返回total的引用。

    定義類相關的非成員函數

    類的作者常常需要定義一些輔助函數,比如 add、read和 print等。盡管這些函數定義的操作從概念上來說屬于類的接口的組成部分,但它們實際上并不屬于類本身。

    我們定義非成員函數的方式與定義其他函數一樣,通常把函數的聲明和定義分離開來。如果函數在概念上屬于類但是不定義在類中,則它一般應與類聲明(而非定義)在同一個頭文件內。在這種方式下,用戶使用接口的任何部分都只需要引入一個文件。

    Note:一般來說,如果非成員函數是類接口的組成部分,則這些函數的聲明應該與類在同一個頭文件內。

    定義read和print函數

    // input transactions contain ISBN, number of copies sold, and sales price istream &read(istream &is, Sales_data &item) {double price = 0;is >> item.bookNo >> item.units_sold >> price;item.revenue = price * item.units_sold;return is; }ostream &print(ostream &os, const Sales_data &item) {os << item.isbn() << " " << item.units_sold << " "<< item.revenue << " " << item.avg_price();return os; }

    read函數從給定流中將數據讀到給定的對象里,print函數則負責將給定對象的內容打印到給定的流中。

    除此之外,關于上面的函數還有兩點是非常重要的。第一點,read和print分別接受一個各自IO類型的引用作為其參數,這是因為IO類屬于不能被拷貝的類型,因此我們只能通過引用來傳遞它們。而且,因為讀取和寫入的操作會改變流的內容,所以兩個函數接受的都是普通引用,而非對常量的引用。(MyNote:is, os不用const修飾,因為讀取和寫入的操作會改變流的內容)

    第二點,print函數不負責換行。一般來說,執行輸出任務的函數應該盡量減少對格式的控制,這樣可以確保由用戶代碼來決定是否換行。

    定義add函數

    add函數接受兩個Sales_data對象作為其參數,返回值是一個新的Sales_data,用于表示前兩個對象的和:

    Sales_data add(const Sales_data &lhs, const Sales_data &rhs) {Sales_data sum = lhs; // copy data members from lhs into sumsum.combine(rhs); // add data members from rhs into sumreturn sum; }

    在函數體中,我們定義了一個新的Sales_data對象并將其命名為sum。sum將用于存放兩筆交易的和,我們用lhs的副本來初始化 sum。默認情況下,拷貝類的對象其實拷貝的是對象的數據成員。在拷貝工作完成之后,sum的bookNo.units_sold和revenue將和lhs一致。接下來我們調用combine函數,將rhs 的units_sold和revenue添加給sum。最后,函數返回sum的副本。

    構造函數

    每個類都分別定義了它的對象被初始化的方式,類通過一個或幾個特殊的成員函數來控制其對象的初始化過程,這些函數叫做構造函數(constructor)。構造函數的任務是初始化類對象的數據成員,無論何時只要類的對象被創建,就會執行構造函數。

    在這一節中,我們將介紹定義構造函數的基礎知識。構造函數是一個非常復雜的問題,我們還會在本章末和第13,15,18章介紹更多關于構造函數的知識。

    構造函數的名字和類名相同。和其他函數不一樣的是,構造函數沒有返回類型;除此之外類似于其他的函數,構造函數也有一個(可能為空的)參數列表和一個(可能為空的)函數體。類可以包含多個構造函數,和其他重載函數差不多,不同的構造函數之間必須在參數數量或參數類型上有所區別。

    不同于其他成員函數,構造函數不能被聲明成const的。當我們創建類的一個const對象時,直到構造函數完成初始化過程,對象才能真正取得其“常量”屬性。因此,構造函數在const對象的構造過程中可以向其寫值。

    合成的默認構造函數

    我們的Sales_data類并沒有定義任何構造函數,可是之前使用了Sales_data對象的程序仍然可以正確地編譯和運行。舉個例子,程序定義了兩個對象:

    Sales_data total; //保存當前求和結果的變量 Sales_data trans; //保存下一條交易數據的變量

    這時我們不禁要問:total和trans是如何初始化的呢?

    我們沒有為這些對象提供初始值,因此我們知道它們執行了默認初始化。類通過一個特殊的構造函數來控制默認初始化過程,這個函數叫做默認構造函數( default constructor)。默認構造函數無須任何實參。

    如我們所見,默認構造函數在很多方面都有其特殊性。其中之一是,如果我們的類沒有顯式地定義構造函數,那么編譯器就會為我們隱式地定義一個默認構造函數。

    編譯器創建的構造函數又被稱為合成的默認構造函數(synthesized default constructor)。對于大多數類來說,這個合成的默認構造函數將按照如下規則初始化類的數據成員:

    • 如果存在類內的初始值,用它來初始化成員。
    • 否則,默認初始化該成員。

    因為Sales_data為units_sold和revenue提供了初始值,所以合成的默認構造函數將使用這些值來初始化對應的成員;同時,它把 bookNo默認初始化成一個空字符串。

    某些類不能依賴于合成的默認構造函數

    合成的默認構造函數只適合非常簡單的類,比如現在定義的這個Sales_data版本。對于一個普通的類來說,必須定義它自己的默認構造函數,原因有三:

    第一個原因也是最容易理解的一個原因就是編譯器只有在發現類不包含任何構造函數的情況下才會替我們生成一個默認的構造函數。一旦我們定義了一些其他的構造函數,那么除非我們再定義一個默認的構造函數,否則類將沒有默認構造函數。這條規則的依據是,如果一個類在某種情況下需要控制對象初始化,那么該類很可能在所有情況下都需要控制。

    Note:只有當類沒有聲明任何構造函數時,編譯器才會自動地生成默認構造函數。

    第二個原因是對于某些類來說,合成的默認構造函數可能執行錯誤的操作。回憶我們之前介紹過的,如果定義在塊中的內置類型或復合類型(比如數組和指針)的對象被默認初始化,則它們的值將是未定義的。該準則同樣適用于默認初始化的內置類型成員。因此,含有內置類型或復合類型成員的類應該在類的內部初始化這些成員,或者定義一個自己的默認構造函數。否則,用戶在創建類的對象時就可能得到未定義的值。

    WARNING:如果類包含有內置類型或者復合類型的成員,則只有當這些成員全都被賦予了類內的初始值時,這個類才適合于使用合成的默認構造函數。

    第三個原因是有的時候編譯器不能為某些類合成默認的構造函數。例如,如果類中包含一個其他類類型的成員且這個成員的類型沒有默認構造函數,那么編譯器將無法初始化該成員。對于這樣的類來說,我們必須自定義默認構造函數,否則該類將沒有可用的默認構造函數。在第13章中我們將看到還有其他一些情況也會導致編譯器無法生成一個正確的默認構造函數。

    定義Sales_data的構造函數

    對于我們的Sales_data類來說,我們將使用下面的參數定義4個不同的構造函數

    • 一個istream&,從中讀取一條交易信息。
    • 一個const string&,表示ISBN編號;一個unsigned,表示售出的圖書數量;以及一個 double,表示圖書的售出價格。
    • 一個const string&,表示ISBN編號;編譯器將賦予其他成員默認值。
    • 一個空參數列表(即默認構造函數),正如剛剛介紹的,既然我們已經定義了其他構造函數,那么也必須定義一個默認構造函數。
    struct Sales_data {// constructors addedSales_data() = default;Sales_data(const std::string &s): bookNo(s) { }Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(std::istream &);// other members as beforestd::string isbn() const {return bookNo;}Sales_data& combine(const Sales_data&);double avg_price() const;std::string bookNo;unsigned units_sold = 0;double revenue = 0.0; };

    = default的含義

    我們從解釋默認構造函數的含義開始:

    Sales_data() = default ;

    首先請明確一點:因為該構造函數不接受任何實參,所以它是一個默認構造函數。我們定義這個構造函數的目的僅僅是因為我們既需要其他形式的構造函數,也需要默認的構造函數。我們希望這個函數的作用完全等同于之前使用的合成默認構造函數。

    在C++11新標準中,如果我們需要默認的行為,那么可以通過在參數列表后面寫上**= default**來要求編譯器生成構造函數。其中,= default 既可以和聲明一起出現在類的內部,也可以作為定義出現在類的外部。和其他函數一樣,如果= default在類的內部,則默認構造函數是內聯的;如果它在類的外部,則該成員默認情況下不是內聯的。

    WARNING:上面的默認構造函數之所以對Sales_data有效,是因為我們為內置類型的數據成員提供了初始值。如果你的編譯器不支持類內初始值,那么你的默認構造函數就應該使用構造函數初始值列表(馬上就會介紹)來初始化類的每個成員。

    構造函數初始化列表

    Sales_data(const std::string &s): bookNo(s) { } Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }

    這兩個定義中出現了新的部分,即冒號以及冒號和花括號之間的代碼,其中花括號定義了(空的)函數體。我們把新出現的部分稱為構造函數初始值列表(constructor initialize list),它負責為新創建的對象的一個或幾個數據成員賦初值。構造函數初始值是成員名字的一個列表,每個名字后面緊跟括號括起來的(或者在花括號內的)成員初始值。不同成員的初始化通過逗號分隔開來。

    含有三個參數的構造函數分別使用它的前兩個參數初始化成員 bookNo和units_sold,revenue 的初始值則通過將售出圖書總數和每本書單價相乘計算得到。

    只有一個string類型參數的構造函數使用這個string對象初始化 bookNo,對于units_sold和 revenue則沒有顯式地初始化。當某個數據成員被構造函數初始值列表忽略時,它將以與合成默認構造函數相同的方式隱式初始化。在此例中,這樣的成員使用類內初始值初始化,因此只接受一個string參數的構造函數等價于

    //與上面定義的那個構造函數效果相同 Sales_data (const std::string &s):bookNo(s) , units_sold(0) , revenue(0){ }

    通常情況下,構造函數使用類內初始值不失為一種好的選擇,因為只要這樣的初始值存在我們就能確保為成員賦予了一個正確的值。不過,如果你的編譯器不支持類內初始值,則所有構造函數都應該顯式地初始化每個內置類型的成員。

    Best Practices:構造函數不應該輕易覆蓋掉類內的初始值,除非新賦的值與原值不同。如果你不能使用類內初始值,則所有構造函數都應該顯式地初始化每個內置類型的成員。

    有一點需要注意,在上面的兩個構造函數中函數體都是空的。這是因為這些構造函數的唯一目的就是為數據成員賦初值,一旦沒有其他任務需要執行,函數體也就為空了。

    在類的外部定義構造函數

    與其他幾個構造函數不同,以istream為參數的構造函數需要執行一些實際的操作。在它的函數體內,調用了read函數以給數據成員賦以初值:

    Sales_data::Sales_data(std::istream &is){read(is, *this); // read函數的作用是從is中讀取一條交易信息然后//存入this對象中 }

    構造函數沒有返回類型,所以上述定義從我們指定的函數名字開始。和其他成員函數一樣,當我們在類的外部定義構造函數時,必須指明該構造函數是哪個類的成員。因此,Sales_data::Sales_data的含義是我們定義Sales_data類的成員,它的名字是Sales_data。又因為該成員的名字和類名相同,所以它是一個構造函數。

    這個構造函數沒有構造函數初始值列表,或者講得更準確一點,它的構造函數初始值列表是空的。盡管構造函數初始值列表是空的,但是由于執行了構造函數體,所以對象的成員仍然能被初始化。

    沒有出現在構造函數初始值列表中的成員將通過相應的類內初始值(如果存在的話)初始化,或者執行默認初始化。對于Sales_data來說,這意味著一旦函數開始執行,則bookNo將被初始化成空string對象,而units_sold和revenue將是0。

    為了更好地理解調用函數read 的意義,要特別注意read的第二個參數是一個Sales_data對象的引用。在中曾經提到過,使用this來把對象當成一個整體訪問,而非直接訪問對象的某個成員。因此在此例中,我們使用*this 將“this”對象作為實參傳遞給read函數。

    // 上文的read函數 // input transactions contain ISBN, number of copies sold, and sales price istream &read(istream &is, Sales_data &item) {double price = 0;is >> item.bookNo >> item.units_sold >> price;item.revenue = price * item.units_sold;return is; }

    拷貝、賦值和析構

    除了定義類的對象如何初始化之外,類還需要控制拷貝、賦值和銷毀對象時發生的行為。

    對象在幾種情況下會被拷貝,如我們初始化變量以及以值的方式傳遞或返回一個對象等(參見第6章的傳參與返回章節)。

    當我們使用了賦值運算符時會發生對象的賦值操作。

    當對象不再存在時執行銷毀的操作,比如一個局部對象會在創建它的塊結束時被銷毀,當vector對象(或者數組)銷毀時存儲在其中的對象也會被銷毀。

    如果我們不主動定義這些操作,則編譯器將替我們合成它們。一般來說,編譯器生成的版本將對對象的每個成員執行拷貝、賦值和銷毀操作。例如,當編譯器執行如下賦值語句時,

    total = trans; //處理下一本書的信息

    它的行為與下面的代碼相同

    //Sales_data的默認賦值操作等價于: total.bookNo = trans.bookNo; total.units_sold = trans.units_sold; total.revenue = trans.revenue;

    我們將在第13章中介紹如何自定義上述操作。

    某些類不能依賴于合成的版本

    盡管編譯器能替我們合成拷貝、賦值和銷毀的操作,但是必須要清楚的一點是,對于某些類來說合成的版本無法正常工作。特別是,當類需要分配類對象之外的資源時,合成的版本常常會失效。舉個例子,第12章將介紹C++程序是如何分配和管理動態內存的。而在而第13章我們將會看到,管理動態內存的類通常不能依賴于上述操作的合成版本。

    不過值得注意的是,很多需要動態內存的類能(而且應該)使用vector對象或者string對象管理必要的存儲空間。使用vector或者string 的類能避免分配和釋放內存帶來的復雜性。However, it is worth noting that many classes that need dynamic memory can (and generally should) use a vector or a string to manage the necessary storage. Classes that use vectors and strings avoid the complexities involved in allocating and deallocating memory.

    進一步講,如果類包含vector或者string 成員,則其拷貝、賦值和銷毀的合成版本能夠正常工作。當我們對含有vector成員的對象執行拷貝或者賦值操作時,vector類會設法拷貝或者賦值成員中的元素。當這樣的對象被銷毀時,將銷毀vector對象,也就是依次銷毀vector中的每一個元素。這一點與string是非常類似的。

    WARNING:在學習第13章關于如何自定義操作的知識之前,類中所有分配的資源都應該直接以類的數據成員的形式存儲。

    訪問控制與封裝

    到目前為止,我們已經為類定義了接口,但并沒有任何機制強制用戶使用這些接口。我們的類還沒有封裝,也就是說,用戶可以直達Sales_data對象的內部并且控制它的具體實現細節。在C++語言中,我們使用訪問說明符(access specifiers)加強類的封裝性:

    • 定義在public說明符之后的成員在整個程序內可被訪問,public成員定義類的接口。
    • 定義在private說明符之后的成員可以被類的成員函數訪問,但是不能被使用該類的代碼訪問,private部分封裝了(即隱藏了)類的實現細節。

    再一次定義Sales_data類,其新形式如下所示:

    class Sales_data {public: // access specifier addedSales_data() = default;Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(const std::string &s): bookNo(s) { }Sales_data(std::istream&);std::string isbn() const { return bookNo; }Sales_data &combine(const Sales_data&);private: // access specifier addeddouble avg_price() const {return units_sold ? revenue / units_sold : 0;}std::string bookNo;unsigned units_sold = 0;double revenue = 0.0; };

    使用class或struct關鍵字

    在上面的定義中我們還做了一個微妙的變化,我們使用了class關鍵字而非struct開始類的定義。這種變化僅僅是形式上有所不同,實際上我們可以使用這兩個關鍵字中的任何一個定義類。唯一的一點區別是,struct和class的默認訪問權限不太一樣

    類可以在它的第一個訪問說明符之前定義成員,對這種成員的訪問權限依賴于類定義的方式。如果我們使用struct關鍵字,則定義在第一個訪問說明符之前的成員是public的;相反,如果我們使用class 關鍵字,則這些成員是private的。

    出于統一編程風格的考慮,當我們希望定義的類的所有成員是 public的時,使用struct;反之,如果希望成員是private的,使用class。

    WARNING:使用class和struct定義類唯一的區別就是默認的訪問權限。

    友元

    既然Sales_data 的數據成員是private的,我們的read、print和 add函數也就無法正常編譯了,這是因為盡管這幾個函數是類的接口的一部分,但它們不是類的成員。

    類可以允許其他類或者函數訪問它的非公有成員,方法是令其他類或者函數成為它的友元(friend)。如果類想把一個函數作為它的友元,只需要增加一條以friend關鍵字開始的函數聲明語句即可:

    class Sales_data {// friend declarations for nonmember Sales_data operations addedfriend Sales_data add(const Sales_data&, const Sales_data&);friend std::istream &read(std::istream&, Sales_data&);friend std::ostream &print(std::ostream&, const Sales_data&);// other members and access specifiers as beforepublic:Sales_data() = default;Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(const std::string &s): bookNo(s) { }Sales_data(std::istream&);std::string isbn() const { return bookNo; }Sales_data &combine(const Sales_data&);private:std::string bookNo;unsigned units_sold = 0;double revenue = 0.0; };// declarations for nonmember parts of the Sales_data interface Sales_data add(const Sales_data&, const Sales_data&); std::istream &read(std::istream&, Sales_data&); std::ostream &print(std::ostream&, const Sales_data&);

    友元聲明只能出現在類定義的內部,但是在類內出現的具體位置不限。友元不是類的成員也不受它所在區域訪問控制級別的約束。我們將在下章節介紹更多關于友元的知識。

    Tip:一般來說,最好在類定義開始或結束前的位置集中聲明友元。

    (MyNote:友元,好朋友聲明,在類內部聲明,表示這些函數是我類的好朋友,它們可以訪問我們成員變量。)

    關鍵概念:封裝的益處

    封裝有兩個重要的優點:

    • 確保用戶代碼不會無意間破壞封裝對象的狀態。

    • 被封裝的類的具體實現細節可以隨時改變,而無須調整用戶級別的代碼。

    一旦把數據成員定義成private的,類的作者就可以比較自由地修改數據了。當實現部分改變時,我們只需要檢查類的代碼本身以確認這次改變有什么影響;換句話說,只要類的接口不變,用戶代碼就無須改變。如果數據是public的,則所有使用了原來數據成員的代碼都可能失效,這時我們必須定位并重寫所有依賴于老版本實現的代碼,之后才能重新使用該程序。

    把數據成員的訪問權限設成 private還有另外一個好處,這么做能防止由于用戶的原因造成數據被破壞。如果我們發現有程序缺陷破壞了對象的狀態,則可以在有限的范圍內定位缺陷:因為只有實現部分的代碼可能產生這樣的錯誤。因此,將查錯限制在有限范圍內將能極大地降低維護代碼及修正程序錯誤的難度。

    Note:盡管當類的定義發生改變時無須更改用戶代碼,但是使用了該類的源文件必須重新編譯。

    友元的聲明

    友元的聲明僅僅指定了訪問的權限,而非一個通常意義上的函數聲明。如果我們希望類的用戶能夠調用某個友元函數,那么我們就必須在友元聲明之外再專門對函數進行一次聲明。

    為了使友元對類的用戶可見,我們通常把友元的聲明與類本身放置在同一個頭文件中(類的外部)。因此,我們的Sales_data頭文件應該為read、print和 add提供獨立的聲明(除了類內部的友元聲明之外)。

    Note:許多編譯器并未強制限定友元函數必須在使用之前在類的外部聲明。

    一些編1譯器允許在尚無友元函數的初始聲明的情況下就調用它。不過即使你的編譯器支持這種行為,最好還是提供一個獨立的函數聲明。這樣即使你更換了一個有這種強制要求的編譯器,也不必改變代碼。

    類的其他特性

    類成員再探

    為了展示這些新的特性,我們需要定義一對相互關聯的類,它們分別是Screen和Window_mgr。

    定義一個類型成員

    Screen表示顯示器中的一個窗口。每個Screen包含一個用于保存Screen內容的string成員和三個String::size_type類型的成員,它們分別表示光標的位置以及屏幕的高和寬。

    除了定義數據和函數成員之外,類還可以自定義某種類型在類中的別名。由類定義的類型名字和其他成員一樣存在訪問限制,可以是public或者private中的一種:

    class Screen {public:typedef std::string::size_type pos;private:pos cursor = 0;pos height = 0, width = 0;std::string contents; };

    我們在Screen的public部分定義了pos,這樣用戶就可以使用這個名字。Screen的用戶不應該知道Screen使用了一個string對象來存放它的數據,因此通過把pos定義成public成員可以隱藏Screen實現的細節。

    關于 pos 的聲明有兩點需要注意。首先,我們使用了typedef,也可以等價地使用類型別名:

    class Screen {public://使用類型別名等價地聲明一個類型名字using pos = std::string::size_type;//其他成員與之前的版本一致 };

    其次,用來定義類型的成員必須先定義后使用,這一點與普通成員有所區別,具體原因隨后解釋。因此,類型成員通常出現在類開始的地方。

    Screen類的成員函數

    要使我們的類更加實用,還需要添加一個構造函數令用戶能夠定義屏幕的尺寸和內容,以及其他兩個成員,分別負責移動光標和讀取給定位置的字符:

    class Screen {public:typedef std::string::size_type pos;Screen() = default; // needed because Screen has another constructor// cursor initialized to 0 by its in-class initializer//令用戶能夠定義屏幕的尺寸和內容Screen(pos ht, pos wd, char c): height(ht), width(wd),contents(ht * wd, c) { }char get() const // get the character at the cursor {return contents[cursor]; // implicitly inline}// 讀取給定位置的字符inline char get(pos ht, pos wd) const; // explicitly inline//移動光標Screen &move(pos r, pos c); // can be made inline laterprivate:pos cursor = 0;pos height = 0, width = 0;std::string contents; };

    因為我們已經提供了一個構造函數,所以編譯器將不會自動生成默認的構造函數。如果我們的類需要默認構造函數,必須顯式地把它聲明出來。在此例中,我們使用=default告訴編譯器為我們合成默認的構造函數。

    需要指出的是,第二個構造函數(接受三個參數)為cursor成員隱式地使用了類內初始值。如果類中不存在cursor的類內初始值,我們就需要像其他成員一樣顯式地初始化 cursor 了。

    令成員作為內聯函數

    在類中,常有一些規模較小的函數適合于被聲明成內聯函數。如我們之前所見的,定義在類內部的成員函數是自動inline的。因此,Screen的構造函數和返回光標所指字符的get函數默認是inline函數。

    我們可以在類的內部把inline作為聲明的一部分顯式地聲明成員函數,同樣的,也能在類的外部用inline關鍵字修飾函數的定義:

    inline // we can specify inline on the definition Screen &Screen::move(pos r, pos c) {pos row = r * width; // compute the row locationcursor = row + c ; // move cursor to the column within that rowreturn *this; // return this object as an lvalue }char Screen::get(pos r, pos c) const // declared as inline in the class {pos row = r * width; // compute row locationreturn contents[row + c]; // return character at the given column }

    雖然我們無須在聲明和定義的地方同時說明inline,但這么做其實是合法的。不過,最好只在類外部定義的地方說明inline,這樣可以使類更容易理解。

    Note:和我們在頭文件中定義inline函數的原因一樣,inline成員函數也應該與相應的類定義在同一個頭文件中。

    重載成員函數

    和非成員函數一樣,成員函數也可以被重載,只要函數之間在參數的數量和/或類型上有所區別就行。成員函數的函數匹配過程同樣與非成員函數非常類似。

    舉個例子,我們的Screen類定義了兩個版本的get函數。

  • 一個版本返回光標當前位置的字符;

  • 另一個版本返回由行號和列號確定的位置的字符。

  • 編譯器根據實參的數量來決定運行哪個版本的函數:

    Screen myScreen ; char ch = myScreen.get();//調用Screen::get() ch = myScreen.get (0, 0);//調用Screen::get(pos, pos)

    可變數據成員

    有時(但并不頻繁)會發生這樣一種情況,我們希望能修改類的某個數據成員,即使是在一個const成員函數內??梢酝ㄟ^在變量的聲明中加入mutable關鍵字做到這一點。

    一個可變數據成員(mutable data member)永遠不會是const,即使它是const對象的成員。因此,一個const 成員函數可以改變一個可變成員的值。舉個例子,我們將給Screen添加一個名為access_ctr的可變成員,通過它我們可以追蹤每個Screen的成員函數被調用了多少次:

    class Screen { public:void some_member() const; private:mutable size_t access_ctr; // may change even in a const object// other members as before };void Screen::some_member() const {++access_ctr; // keep a count of the calls to any member function// whatever other work this member needs to do }

    盡管some_member是一個const成員函數,它仍然能夠改變access_ctr的值。該成員是個可變成員,因此任何成員函數,包括const函數在內都能改變它的值。

    類數據成員的初始值

    在定義好Screen類之后,我們將繼續定義一個窗口管理類并用它表示顯示器上的一組 Screen。這個類將包含一個Screen類型的 vector,每個元素表示一個特定的Screen。默認情況下,我們希望window_mgr類開始時總是擁有一個默認初始化的
    Screen。在C++11新標準中,最好的方式就是把這個默認值聲明成一個類內初始值:

    class window_mgr {private://這個window_mgr追蹤的Screen//默認情況下,一個window_mgr包含一個標準尺寸的空白Screenstd::vector<Screen> Screens{Screen (24,80' ')}; };

    當我們初始化類類型的成員時,需要為構造函數傳遞一個符合成員類型的實參。在此例中,我們使用一個單獨的元素值對vector成員執行了列表初始化,這個 Screen 的值被傳遞給vector<Screen>的構造函數,從而創建了一個單元素的vector對象。

    具體地說,Screen 的構造函數接受兩個尺寸參數和一個字符值,創建了一個給定大小的空白屏幕對象。

    如我們之前所知的,類內初始值必須使用=的初始化形式(初始化Screen的數據成員時所用的)或者花括號括起來的直接初始化形式(初始化Screens所用的)。

    Note:當我們提供一個類內初始值時,必須以符號=或者花括號表示。

    返回*this的成員函數

    接下來我們繼續添加一些函數,它們負責設置光標所在位置的字符或者其他任一給定位置的字符

    class Screen { public:Screen &set(char);Screen &set(pos, pos, char);// other members as before };inline Screen &Screen::set(char c) {contents[cursor] = c; // set the new value at the current cursor locationreturn *this; // return this object as an lvalue }inline Screen &Screen::set(pos r, pos col, char ch) {contents[r * width + col] = ch; // set specified location to givenvaluereturn *this; // return this object as an lvalue }

    和move操作一樣,我們的set成員的返回值是調用set的對象的引用。返回引用的函數是左值的,意味著這些函數返回的是對象本身而非對象的副本。如果我們把一系列這樣的操作連接在一條表達式中的話:

    //把光標移動到一個指定的位置,然后設置該位置的字符值 myScreen.move(4, 0).set ('#’);

    這些操作將在同一個對象上執行。在上面的表達式中,我們首先移動myScreen內的光標,然后設置myScreen 的contents成員。也就是說,上述語句等價于

    myScreen.move(4,0); myScreen.set('#');

    如果我們令move和set返回Screen而非Screen&,則上述語句的行為將大不相同。在此例中等價于:

    //如果move返回Screen而非Screen& Screen temp = myScreen.move(4, 0);//對返回值進行拷貝 temp.set('#');//不會改變myScreen的contents

    假如當初我們定義的返回類型不是引用,則move的返回值將是*this的副本,因此調用set 只能改變臨時副本,而不能改變myScreen的值。

    從const成員函數返回*this,它的返回類型將是常量引用

    接下來,我們繼續添加一個名為display的操作,它負責打印Screen的內容。我們希望這個函數能和move 以及 set出現在同一序列中,因此類似于move和set,display函數也應該返回執行它的對象的引用。

    從邏輯上來說,顯示一個Screen并不需要改變它的內容,因此我們令display為一個const成員,此時,this將是一個指向const的指針而*this是 const對象。由此推斷,display的返回類型應該是const Sales_data&。然而,如果真的令display返回一個const 的引用,則我們將不能把display嵌入到一組動作的序列中去:

    Screen myScreen; //如果display返回常量引用,則調用set將引發錯誤 myScreen.display(cout).set('*');

    即使myScreen是個非常量對象,對set的調用也無法通過編譯。問題在于display的const版本返回的是常量引用,而我們顯然無權set一個常量對象。

    Note:一個const成員函數如果以引用的形式返回*this,那么它的返回類型將是常量引用。

    基于const的重載

    通過區分成員函數是否是const 的,我們可以對其進行重載,其原因與我們之前根據指針參數是否指向const而重載函數的原因差不多。具體說來,因為非常量版本的函數對于常量對象是不可用的,所以我們只能在一個常量對象上調用const 成員函數。另一方面,雖然可以在非常量對象上調用常量版本或非常量版本,但顯然此時非常量版本是一個更好的匹配。

    在下面的這個例子中,我們將定義一個名為 do_display的私有成員,由它負責打印Screen的實際工作。所有的display操作都將調用這個函數,然后返回執行操作的對象:

    class Screen { public:// display overloaded on whether the object is const or notScreen &display(std::ostream &os){ do_display(os); return *this; }const Screen &display(std::ostream &os) const{ do_display(os); return *this; } private:// function to do the work of displaying a Screenvoid do_display(std::ostream &os) const {os << contents;}// other members as before };

    和我們之前所學的一樣,當一個成員調用另外一個成員時,this指針在其中隱式地傳遞。因此,

    • 當display調用do_display時,它的this指針隱式地傳遞給do_display。
    • 而當display的非常量版本調用do_display時,它的this指針將隱式地從指向非常量的指針轉換成指向常量的指針。

    當do_display完成后,display函數各自返回解引用this所得的對象。

    • 在非常量版本中,this指向一個非常量對象,因此display返回一個普通的(非常量)引用;
    • 而const成員則返回一個常量引用。

    當我們在某個對象上調用display 時,該對象是否是 const決定了應該調用display的哪個版本:

    Screen myScreen(5,3); const Screen blank(5, 3); myScreen.set('#').display(cout); // calls non const version blank.display(cout); // calls const version

    建議:對于公共代碼使用私有功能函數

    有些讀者可能會奇怪為什么我們要費力定義一個單獨的do_display函數。畢竟,對do_display的調用并不比 do_display函數內部所做的操作簡單多少。為什么還要這么做呢?實際上我們是出于以下原因的?

    • 一個基本的愿望是避免在多處使用同樣的代碼。
    • 我們預期隨著類的規模發展,display函數有可能變得更加復雜,此時,把相應的操作寫在一處而非兩處的作用就比較明顯了。
    • 我們很可能在開發過程中給do_display函數添加某些調試信息,而這些信息將在代碼的最終產品版本中去掉。顯然,只在 do_display一處添加或刪除這些信息要更容易一些。
    • 這個額外的函數調用不會增加任何開銷。因為我們在類內部定義了do_display,所以它隱式地被聲明成內聯函數。這樣的話,調用 do_display就不會帶來任何額外的運行時開銷。

    在實踐中,設計良好的C++代碼常常包含大量類似于do_display的小函數,通過調用這些函數,可以完成一組其他函數的“實際”工作。

    (MyNote:重復代碼->重構。)

    類類型

    每個類定義了唯一的類型。對于兩個類來說,即使它們的成員完全一樣,這兩個類也是兩個不同的類型。例如:

    struct First{int memi;int getMem(); }; struct Second{int memi;int getMem(); }; First obj1; second obj2 = obj1; //錯誤:obj1和obj2的類型不同

    Note:即使兩個類的成員列表完全一致,它們也是不同的類型。對于一個類來說,它的成員和其他任何類(或者任何其他作用域)的成員都不是一回事兒。

    我們可以把類名作為類型的名字使用,從而直接指向類類型?;蛘?#xff0c;我們也可以把類名跟在關鍵字class或struct后面:

    Sales_data iteml; //默認初始化Sales_data類型的對象 class Sales_data iteml; //一條等價的聲明

    上面這兩種使用類類型的方式是等價的,其中第二種方式從C語言繼承而來,并且在C++語言中也是合法的。

    類的聲明(可先聲明,暫時不定義)

    就像可以把函數的聲明和定義分離開來一樣,我們也能僅僅聲明類而暫時不定義它:

    class Screen;// Screen類的聲明

    這種聲明有時被稱作前向聲明(forward declaration),它向程序中引入了名字Screen并且指明Screen是一種類類型。對于類型Screen來說,在它聲明之后定義之前是一個不完全類型(incomplete type),也就是說,此時我們已知Screen是一個類類型,但是不清楚它到底包含哪些成員。

    不完全類型只能在非常有限的情景下使用:可以定義指向這種類型的指針或引用,也可以聲明(但是不能定義)以不完全類型作為參數或者返回類型的函數。

    對于一個類來說,在我們創建它的對象之前該類必須被定義過,而不能僅僅被聲明。否則,編譯器就無法了解這樣的對象需要多少存儲空間。類似的,類也必須首先被定義,然后才能用引用或者指針訪問其成員。畢竟,如果類尚未定義,編譯器也就不清楚該類到底有哪些成員。(MyNote:只聲明不定義的局限)

    隨后我們將描述一種例外的情況:直到類被定義之后數據成員才能被聲明成這種類類型。換句話說,我們必須首先完成類的定義,然后編譯器才能知道存儲該數據成員需要多少空間。因為只有當類全部完成后類才算被定義,所以一個類的成員類型不能是該類自己。

    然而,一旦一個類的名字出現后,它就被認為是聲明過了(但尚未定義),因此類允許包含指向它自身類型的引用或指針:

    class Link_Screen {Screen window;Link_Screen *next;Link_Screen *prev; };

    友元再探

    我們的Sales_data類把三個普通的非成員函數定義成了友元。類還可以把其他的類定義成友元,也可以把其他類(之前已定義過的)的成員函數定義成友元。此外,友元函數能定義在類的內部,這樣的函數是隱式內聯的。

    類之間的友元關系

    舉個友元類的例子,我們的Window_mgr類的某些成員可能需要訪問它管理的Screen類的內部數據。例如,假設我們需要為Window_mgr添加一個名為 clear的成員,它負責把一個指定的Screen的內容都設為空白。為了完成這一任務,clear需要訪問Screen的私有成員;而要想令這種訪問合法,Screen需要把Window_mgr指定成它的友元:

    class Screen {// Window_mgr members can access the private parts of class Screenfriend class Window_mgr;// ... rest of the Screen class };

    如果一個類指定了友元類,則友元類的成員函數可以訪問此類包括非公有成員在內的所有成員。通過上面的聲明,Window_mgr被指定為Screen的友元,因此我們可以將Window_mgr的clear成員寫成如下的形式:

    class Window_mgr { public:// location ID for each Screen on the windowusing ScreenIndex = std::vector<Screen>::size_type;// reset the Screen at the given position to all blanksvoid clear(ScreenIndex); private:std::vector<Screen> Screens{Screen(24, 80, ' ')}; };void Window_mgr::clear(ScreenIndex i) {// s is a reference to the Screen we want to clearScreen &s = Screens[i];// reset the contents of that Screen to all blankss.contents = string(s.height * s.width, ' '); }

    一開始,首先把s定義成Screens vector中第i個位置上的Screen的引用,隨后利用Screen的height和 width成員計算出一個新的string對象,并令其含有若干個空白字符,最后我們把這個含有很多空白的字符串賦給contents成員。

    如果clear不是Screen的友元,上面的代碼將無法通過編譯,因為此時clear將不能訪問Screen的height、width和contents成員。而當Screen將window_mgr指定為其友元之后,Screen 的所有成員對于window_mgr就都變成可見的了。

    必須要注意的一點是,友元關系不存在傳遞性。也就是說,如果Window_mgr有它自己的友元,則這些友元并不能理所當然地具有訪問Screen的特權。

    Note:每個類負責控制自己的友元類或友元函數。

    令成員函數作為友元

    除了令整個Window_mgr作為友元之外,Screen還可以只為clear提供訪問權限。當把一個成員函數聲明成友元時,我們必須明確指出該成員函數屬于哪個類:(MyNote:進一步細粒度化。)

    class Screen {// Window_mgr::clear must have been declared before class Screenfriend void Window_mgr::clear(ScreenIndex);// ... rest of the Screen class };

    要想令某個成員函數作為友元,我們必須仔細組織程序的結構以滿足聲明和定義的彼此依賴關系。在這個例子中,我們必須按照如下方式設計程序:

    • 首先定義Window_mgr類,其中聲明clear函數,但是不能定義它。在 clear使用Screen的成員之前必須先聲明Screen。
    • 接下來定義Screen,包括對于clear的友元聲明。
    • 最后定義clear,此時它才可以使用Screen的成員。

    函數重載和友元

    盡管重載函數的名字相同,但它們仍然是不同的函數。因此,如果一個類想把一組重載函數聲明成它的友元,它需要對這組函數中的每一個分別聲明:

    // overloaded storeOn functions extern std::ostream& storeOn(std::ostream &, Screen &); extern BitMap& storeOn(BitMap &, Screen &);class Screen { // ostream version of storeOn may access the private parts of Screen objectsfriend std::ostream& storeOn(std::ostream &, Screen &);// . . . };

    友元聲明和作用域

    類和非成員函數的聲明不是必須在它們的友元聲明之前。當一個名字第一次出現在一個友元聲明中時,我們隱式地假定該名字在當前作用域中是可見的。然而,友元本身不一定真的聲明在當前作用域中。(MyNote:再本章前部分的“友元的聲明”有相關說明。)

    甚至就算在類的內部定義該函數,我們也必須在類的外部提供相應的聲明從而使得函數可見。換句話說,即使我們僅僅是用聲明友元的類的成員調用該友元函數,它也必須是被聲明過的:

    struct X {friend void f() { /* friend function can be defined in the class body */ }X() { f(); } // error: no declaration for fvoid g();void h(); };void X::g() { return f(); } // error: f hasn't been declared void f(); // declares the function defined inside X void X::h() { return f(); } // ok: declaration for f is now in scope

    關于這段代碼最重要的是理解友元聲明的作用是影響訪問權限,它本身并非普通意義上的聲明。

    Note:請注意,有的編譯器并不強制執行上述關于友元的限定規則。

    (MyNote:友元函數聲明不同于普通函數聲明,它們是兩碼事。)

    類的作用域

    每個類都會定義它自己的作用域。在類的作用域之外,普通的數據和函數成員只能由對象、引用或者指針使用成員訪問運算符(.)來訪問。對于類類型成員則使用作用域運算符(::)訪問。不論哪種情況,跟在運算符之后的名字都必須是對應類的成員:

    Screen::pos ht = 24, wd = 80; // use the pos type defined by Screen Screen scr(ht, wd, ' '); Screen *p = &scr; char c = scr.get(); // fetches the get member from the object scr c = p->get(); // fetches the get member from the object to which p points

    作用域和定義在類外部的成員

    一個類就是一個作用域的事實能夠很好地解釋為什么當我們在類的外部定義成員函數時必須同時提供類名和函數名。在類的外部,成員的名字被隱藏起來了。

    一旦遇到了類名,定義的剩余部分就在類的作用域之內了,這里的剩余部分包括參數列表和函數體。結果就是,我們可以直接使用類的其他成員而無須再次授權了

    例如,我們回顧一下Window _mgr類的clear成員,該函數的參數用到了Window_mgr類定義的一種類型:

    void Window_mgr::clear(ScreenIndex i) {Screen &s = Screens[i];s.contents = string(s.height * s.width, ' '); }

    因為編譯器在處理參數列表之前已經明確了我們當前正位于Window_mgr類的作用域中,所以不必再專門說明ScreenIndex是Window_mgr類定義的。出于同樣的原因,編譯器也能知道函數體中用到的Screens也是在Window_mgr類中定義的。

    另一方面,函數的返回類型通常出現在函數名之前。因此當成員函數定義在類的外部時,返回類型中使用的名字都位于類的作用域之外。這時,返回類型必須指明它是哪個類的成員。

    例如,我們可能向Window_mgr類添加一個新的名為addScreen的函數,它負責向顯示器添加一個新的屏幕。這個成員的返回類型將是ScreenIndex,用戶可以通過它定位到指定的Screen:

    class Window_mgr { public:// add a Screen to the window and returns its indexScreenIndex addScreen(const Screen&);// other members as before };// return type is seen before we're in the scope of Window_mgr Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s) {Screens.push_back(s);return Screens.size() - 1; }

    因為返回類型出現在類名之前,所以事實上它是位于Window_mgr類的作用域之外的。在這種情況下,要想使用ScreenIndex作為返回類型,我們必須明確指定哪個類定義了它。

    名字查找與類的作用域

    在目前為止,我們編寫的程序中,名字查找(name lookup)(尋找與所用名字最匹配的聲明的過程)的過程比較直截了當:

    • 首先,在名字所在的塊中尋找其聲明語句,只考慮在名字的使用之前出現的聲明。
    • 如果沒找到,繼續查找外層作用域。
    • 如果最終沒有找到匹配的聲明,則程序報錯。

    對于定義在類內部的成員函數來說,解析其中名字的方式與上述的查找規則有所區別,不過在當前的這個例子中體現得不太明顯。類的定義分兩步處理

    • 首先,編譯成員的聲明。
    • 直到類全部可見后才編譯函數體。

    Note:編譯器處理完類中的全部聲明后才會處理成員函數的定義。(MyNote:類中,先全部聲明,后定義)

    按照這種兩階段的方式處理類可以簡化類代碼的組織方式。因為成員函數體直到整個類可見后才會被處理,所以它能使用類中定義的任何名字。

    相反,如果函數的定義和成員的聲明被同時處理,那么我們將不得不在成員函數中只使用那些已經出現的名字。

    用于類成員聲明的名字查找

    這種兩階段的處理方式只適用于成員函數中使用的名字。聲明中使用的名字,包括返回類型或者參數列表中使用的名字,都必須在使用前確??梢?/strong>。如果某個成員的聲明使用了類中尚未出現的名字,則編譯器將會在定義該類的作用域中繼續查找。

    例如:

    typedef double Money; string bal;class Account { public:Money balance() { return bal; } private:Money bal;// ... };

    當編譯器看到balance函數的聲明語句時,它將在Account類的范圍內尋找對Money的聲明。編譯器只考慮Account中在使用Money前出現的聲明,因為沒找到匹配的成員,所以編譯器會接著到Account的外層作用域中查找。

    在這個例子中,編譯器會找到Money的typedef語句,該類型被用作balance函數的返回類型以及數據成員bal的類型。另一方面,balance函數體在整個類可見后才被處理,因此,該函數的return 語句返回名為bal 的成員,而非外層作用域的string對象。

    類型名要特殊處理

    一般來說,內層作用域可以重新定義外層作用域中的名字,即使該名字已經在內層作用域中使用過。然而在類中,如果成員使用了外層作用域中的某個名字,而該名字代表一種類型,則類不能在之后重新定義該名字

    typedef double Money; class Account { public:Money balance() { return bal; } // uses Money from the outer scope private:typedef double Money; // error: cannot redefine MoneyMoney bal;// ... };

    需要特別注意的是,即使Account中定義的Money類型與外層作用域一致,上述代碼仍然是錯誤的。

    盡管重新定義類型名字是一種錯誤的行為,但是編譯器并不為此負責。一些編譯器仍將順利通過這樣的代碼,而忽略代碼有錯的事實。(MyNote:┑( ̄Д  ̄)┍)

    Tip:類型名的定義通常出現在類的開始處,這樣就能確保所有使用該類型的成員都出現在類名的定義之后。

    成員定義中的普通塊作用域的名字查找

    成員函數中使用的名字按照如下方式解析:(MyNote:本節重點)

    • 首先,在成員函數內查找該名字的聲明。和前面一樣,只有在函數使用之前出現的聲明才被考慮。

    • 如果在成員函數內沒有找到,則在類內繼續查找,這時類的所有成員都可以被考慮。

    • 如果類內也沒找到該名字的聲明,在成員函數定義之前的作用域內繼續查找。

    (MyNote:初讀這些界定詞有點繞,結合下面程序理解。)

    一般來說,不建議使用其他成員的名字作為某個成員函數的參數。不過為了更好地解釋名字的解析過程,我們不妨在dummy_fcn函數中暫時違反一下這個約定:

    //注意:這段代碼僅為了說明而用,不是一段很好的代碼 //通常情況下不建議為參數和成員使用同樣的名字 int height; //定義了一個名字,稍后將在Screen中使用 class Screen { public:typedef std::string::size_type pos;void dummy_fcn(pos height) {cursor = width * height; // which height? the parameter} private:pos cursor = 0;pos height = 0, width = 0; };

    當編譯器處理dummy_fcn 中的乘法表達式時,它首先在函數作用域內查找表達式中用到的名字。函數的參數位于函數作用域內,因此 dummy_fcn函數體內用到的名字height指的是參數聲明

    在此例中,height參數隱藏了同名的成員。如果想繞開上面的查找規則,應該將代碼變為:

    // bad practice: names local to member functions shouldn't hide member names void Screen::dummy_fcn(pos height) {cursor = width * this->height; // member height// alternative way to indicate the membercursor = width * Screen::height; // member height }

    Note:盡管類的成員被隱藏了,但我們仍然可以通過加上類的名字或顯式地使用this指針來強制訪問成員。

    其實最好的確保我們使用height成員的方法是給參數起個其他名字:

    //建議的寫法:不要把成員名字作為參數或其他局部變量使用 void Screen::dummy_fcn (pos ht) {cursor = width * height ; //成員height }

    在此例中,當編譯器查找名字height時,顯然在 dummy_fcn函數內部是找不到的。編譯器接著會在Screen內查找匹配的聲明,即使height的聲明出現在dummy_fcn使用它之后,編譯器也能正確地解析函數使用的是名為height的成員。

    類作用域之后,在外圍得作用域中查找

    如果編譯器在函數和類的作用域中都沒有找到名字,它將接著在外圍的作用域中查找。

    在我們的例子中,名字height定義在外層作用域中,且位于Screen的定義之前。然而,外層作用域中的對象被名為height 的成員隱藏掉了。因此,如果我們需要的是外層作用域中的名字,可以顯式地通過作用域運算符來進行請求:

    //不建議的寫法:不要隱藏外層作用域中可能被用到的名字void Screen::dummy_fcn(pos height) {cursor = width * ::height ;//哪個height?是那個全局的 }

    Note:盡管外層的對象被隱藏掉了,但我們仍然可以用作用域運算符訪問它。

    在文件中名字得出現處對其進行解析

    當成員定義在類的外部時,名字查找的第三步不僅要考慮類定義之前的全局作用域中的聲明,還需要考慮在成員函數定義之前的全局作用域中的聲明。例如:

    int height; // defines a name subsequently used inside Screen class Screen { public:typedef std::string::size_type pos;void setHeight(pos);pos height = 0; // hides the declaration of height in the outer scope };Screen::pos verify(Screen::pos); void Screen::setHeight(pos var) {// var: refers to the parameter// height: refers to the class member// verify: refers to the global functionheight = verify(var); }

    請注意,全局函數verify的聲明在Screen類的定義之前是不可見的。然而,名字查找的第三步包括了成員函數出現之前的全局作用域。在此例中,verify的聲明位于setHeight的定義之前,因此可以被正常使用。

    (MyNote:Java變量都定義在類內,C++的類內外都可聲明定義,麻煩不止一點點。)

    (MyNote:C++有關類的作用域:1. 成員函數作用域 2. 類作用域 3.類外圍作用域。本節重點看“成員定義中的普通塊作用域的名字查找”。)

    構造函數再探

    構造函數初始值列表

    當我們定義變量時習慣于立即對其進行初始化,而非先定義、再賦值

    string foo = "Hello world!" ; //定義并初始化 string bar; //默認初始化成空string對象 bar = "Hello world! "; //為bar賦一個新值

    就對象的數據成員而言,初始化和賦值也有類似的區別。**如果沒有在構造函數的初始值列表中顯式地初始化成員,則該成員將在構造函數體之前執行默認初始化。**例如:

    // Sales_data構造函數的一種寫法,雖然合法但比較草率:沒有使用構造函數初始值 Sales_data::Sales_data(const string &s, unsigned cnt, double price){bookNo = s ;units_sold = cnt;revenue = cnt * price; }

    這段代碼和前文的原始定義效果是相同的:

    struct Sales_data {// constructors addedSales_data() = default;Sales_data(const std::string &s): bookNo(s) { }Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(std::istream &);//... };

    當構造函數完成后,數據成員的值相同。區別是原來的版本初始化了它的數據成員,而這個版本是對數據成員執行了賦值操作。這一區別到底會有什么深層次的影響完全依賴于數據成員的類型。

    構造函數的初始值有時必不可少

    有時我們可以忽略數據成員初始化和賦值之間的差異,但并非總能這樣。如果成員是const或者是引用的話,必須將其初始化。類似的,當成員屬于某種類類型且該類沒有定義默認構造函數時,也必須將這個成員初始化。例如:

    class ConstRef { public:ConstRef(int ii); private:int i;const int ci ;int &ri; };

    和其他常量對象或者引用一樣,成員ci和ri都必須被初始化。因此,如果我們沒有為它們提供構造函數初始值的話將引發錯誤:

    //錯誤:ci和ri必須被初始化 ConstRef::ConstRef(int ii){ {//賦值:i = ii ;//正確ci = ii ;//錯誤:不能給const賦值ri = i;//錯誤:ri沒被初始化 }

    隨著構造函數體一開始執行,初始化就完成了。我們初始化 const或者引用類型的數據成員的唯一機會就是通過構造函數初始值,因此該構造函數的正確形式應該是:

    // ok: explicitly initialize reference and const members ConstRef::ConstRef(int ii): i(ii), ci(ii), ri(i) { }

    Note:如果成員是const、引用,或者屬于某種未提供默認構造函數的類類型,我們必須通過構造函數初始值列表為這些成員提供初值

    建議:使用構造函數初始值

    在很多類中,初始化和賦值的區別事關底層效率問題:前者直接初始化數據成員,后者則先初始化再賦值。In many classes, the distinction between initialization and assignment is strictly a matter of low-level efficiency: A data member is initialized and then assigned when it could have been initialized directly.

    除了效率問題外更重要的是,一些數據成員必須被初始化。建議讀者養成使用構造函數初始值的習慣,這樣能避免某些意想不到的編譯錯誤,特別是遇到有的類含有需要構造函數初始值的成員時。

    成員初始化的順序

    顯然,在構造函數初始值中每個成員只能出現一次。否則,給同一個成員賦兩個不同的初始值有什么意義呢?

    不過讓人稍感意外的是,構造函數初始值列表只說明用于初始化成員的值,而不限定初始化的具體執行順序。

    成員的初始化順序與它們在類定義中的出現順序一致:第一個成員先被初始化,然后第二個,以此類推。

    構造函數初始值列表中初始值的前后位置關系不會影響實際的初始化順序。

    一般來說,初始化的順序沒什么特別要求。不過如果一個成員是用另一個成員來初始化的,那么這兩個成員的初始化順序就很關鍵了。

    舉個例子,考慮下面這個類:

    class X {int i;int j; public:// undefined: i is initialized before jX(int val): j(val), i(j) { } };

    在此例中,從構造函數初始值的形式上來看仿佛是先用val初始化了j,然后再用j初始化i。實際上,i先被初始化,因此這個初始值的效果是試圖使用未定義的值j初始化i!

    有的編譯器具備一項比較友好的功能,即當構造函數初始值列表中的數據成員順序與這些成員聲明的順序不符時會生成一條警告信息。

    Best Practices:最好令構造函數初始值的順序與成員聲明的順序保持一致。而且如果可能的話,盡量避免使用某些成員初始化其他成員。

    如果可能的話,最好用構造函數的參數作為成員的初始值,而盡量避免使用同一個對象的其他成員。這樣的好處是我們可以不必考慮成員的初始化順序。

    例如,X的構造函數如果寫成如下的形式效果會更好:

    X(int val):i(val), j(val) { }

    在這個版本中,i和j初始化的順序就沒什么影響了。

    默認實參和構造函數

    Sales_data 默認構造函數的行為與只接受一個string 實參的構造函數差不多。

    唯一的區別是接受String實參的構造函數使用這個實參初始化bookNo,而默認構造函數(隱式地)使用string的默認構造函數初始化bookNo。我們可以把它們重寫成一個使用默認實參(第6章內容)的構造函數:

    class Sales_data { public://定義默認構造函數,令其與只接受一個string實參的構造函數功能相同Sales_data(std::string s = ""):bookNo(s){ }//其他構造函數與之前一致Sales_data(std::string s, unsigned cnt, double rev):bookNo(s) , units_sold(cnt) , revenue (rev * cnt) { }Sales_data(std::istream &is) { read(is, *this); }//其他成員與之前的版本一致 };

    當沒有給定實參,或者給定了一個string實參時,兩個版本的類創建了相同的對象。因為我們不提供實參也能調用上述的構造函數,所以該構造函數實際上為我們的類提供了默認構造函數。

    Note:如果一個構造函數為所有參數都提供了默認實參,則它實際上也定義了默認構造函數。

    值得注意的是,我們不應該為Sales_data接受三個實參的構造函數提供默認值。因為如果用戶為售出書籍的數量提供了一個非零的值,則我們就會期望用戶同時提供這些書籍的售出價格。

    委托構造函數

    C++11新標準擴展了構造函數初始值的功能,使得我們可以定義所謂的委托構造函數(delegating constructor)。一個委托構造函數使用它所屬類的其他構造函數執行它自己的初始化過程,或者說它把它自己的一些(或者全部)職責委托給了其他構造函數。

    和其他構造函數一樣,一個委托構造函數也有一個成員初始值的列表和一個函數體。在委托構造函數內,成員初始值列表只有一個唯一的入口,就是類名本身。和其他成員初始值一樣,類名后面緊跟圓括號括起來的參數列表,參數列表必須與類中另外一個構造函數匹配。

    舉個例子,我們使用委托構造函數重寫Sales_data類,重寫后的形式如下所示:

    class Sales_data { public:// nondelegating constructor initializes members from corresponding arguments//1.Sales_data(std::string s, unsigned cnt, double price):bookNo(s), units_sold(cnt), revenue(cnt*price) {}// remaining constructors all delegate to another constructor//2.Sales_data(): Sales_data("", 0, 0) {}//3.Sales_data(std::string s): Sales_data(s, 0,0) {}//4.Sales_data(std::istream &is): Sales_data() { read(is, *this); }// other members as before };

    在這個Sales_data類中,除了一個構造函數外其他的都委托了它們的工作。

  • 第一個構造函數接受三個實參,使用這些實參初始化數據成員,然后結束工作。

  • 我們定義默認構造函數令其使用三參數的構造函數完成初始化過程,它也無須執行其他任務,這一點從空的構造函數體能看得出來。

  • 接受一個string 的構造函數同樣委托給了三參數的版本。

  • 接受istream&的構造函數也是委托構造函數,它委托給了默認構造函數,默認構造函數又接著委托給三參數構造函數。當這些受委托的構造函數執行完后,接著執行istream&構造函數體的內容。它的構造函數體調用read函數讀取給定的istream。

  • 當一個構造函數委托給另一個構造函數時,受委托的構造函數的初始值列表和函數體皆被執行。在Sales_data類中,受委托的構造函數體恰好是空的。假如函數體包含有代碼的話,將先執行這些代碼,然后控制權才會交還給委托者的函數體。(MyNote:先函數體代碼,再委托構造函數)

    默認構造函數的作用

    當對象被默認初始化(Default initialization) 或 值初始化(Value initialization)(第3章)時自動執行默認構造函數。

    默認初始化在以下情況下發生:

    • 當我們在塊作用域內不使用任何初始值定義一個非靜態變量或者數組時。(第2章)

    • 當一個類本身含有類類型的成員且使用合成的默認構造函數時(本章)。

    • 當類類型的成員沒有在構造函數初始值列表中顯式地初始化時(本章)。

    值初始化在以下情況下發生:

    • 在數組初始化的過程中如果我們提供的初始值數量少于數組的大小時(第3章)。

    • 當我們不使用初始值定義一個局部靜態變量時(第6章)。

    • 當我們通過書寫形如T()的表達式顯式地請求值初始化時,其中T是類型名(vector的一個構造函數只接受一個實參用于說明vector大小(第3章),它就是使用一個這種形式的實參來對它的元素初始化器進行值初始化)。

    類必須包含一個默認構造函數以便在上述情況下使用,其中的大多數情況非常容易判斷。

    不那么明顯的一種情況是類的某些數據成員缺少默認構造函數:

    class NoDefault { public:NoDefault(const std::string&);// additional members follow, but no other constructors };struct A { // my_mem is public by default; NoDefault my_mem; };A a; // error: cannot synthesize a constructor for Astruct B {B() {} // error: no initializer for b_memberNoDefault b_member; //沒有默認構造函數 };

    Best Practices:在實際中,如果定義了其他構造函數,那么最好也提供一個默認構造函數。


    默認初始化(default initialization)當對象未被顯式地賦予初始值時執行的初始化行為。由類本身負責執行的類對象的初始化行為。全局作用域的內置類型對象初始化為0;局部作用域的對象未被初始化即擁有未定義的值。(來自第2章術語表)

    值初始化(value initialization)是種初始化過程。內置類型初始化為0,類類型由類的默認構造函數初始化。只有當類包含默認構造函數時,該類的對象才會被值初始化。對于容器的初始化來說,如果只說明了容器的大小而沒有指定初始值的話,就會執行值初始化。此時編譯器會生成個值,而容器的元素被初始化為該值。(第3章術語表)

    (MyNote:個人沒有感覺默認初始化值初始化這兩個術語有明顯區別。(ーー゛)個人理解:值初始化主要用在數組,容器,其余的都是默認初始化。)

    使用默認構造函數

    下面的obj的聲明可以正常編譯通過:

    Sales_data obj();//正確:定義了一個函數而非對象

    但當我們試圖使用obj 時,編譯器將報錯,提示我們不能對函數使用成員訪問運算符。

    if(obj.isbn () == Primer_5th_ed.isbn())//錯誤:obj是一個函數

    問題在于,盡管我們想聲明一個默認初始化的對象,obj實際的含義卻是一個不接受任何參數的函數并且其返回值是Sales_data類型的對象。

    如果想定義一個使用默認構造函數進行初始化的對象,正確的方法是去掉對象名之后的空的括號對:

    //正確:obj是個默認初始化的對象 Sales_data obj;

    WARNING

    對于C++的新手程序員來說有一種常犯的錯誤,它們試圖以如下的形式聲明一個用默認構造函數初始化的對象

    Sales_data obj();//錯誤:聲明了一個函數而非對象 Sales_data obj2;//正確:obj2是一個對象而非函數

    隱式的類類型轉換

    第4章曾經介紹過C++語言在內置類型之間定義了幾種自動轉換規則。

    同樣的,我們也能為類定義隱式轉換規則。如果構造函數只接受一個實參,則它實際上定義了轉換為此類類型的隱式轉換機制,有時我們把這種構造函數稱作轉換構造函數converting constructor)。

    將在第14章介紹如何定義將一種類類型轉換為另一種類類型的轉換規則。

    Note:能通過一個實參調用的構造函數定義了一條從構造函數的參數類型向類類型隱式轉換的規則。

    在Sales_data類中,接受string 的構造函數和接受 istream的構造函數分別定義了從這兩種類型向 Sales_data 隱式轉換的規則。也就是說,在需要使用Sales_data的地方,我們可以使用string或者istream 作為替代:

    string null_book = "9-999-99999-9" ; //構造一個臨時的Sales_data對象 //該對象的units_sold和revenue等于0,bookNo等于null_book item.combine(null_book);

    在這里我們用一個string實參調用了Sales_data的combine 成員。該調用是合法的,編譯器用給定的string自動創建了一個Sales_data對象。新生成的這個(臨時)Sales_data對象被傳遞給combine。因為combine的參數是一個常量引用,所以我們可以給該參數傳遞一個臨時量。

    只允許一步類類型轉換

    第4章指出,編譯器只會自動地執行一步類型轉換。

    例如,因為下面的代碼隱式地使用了兩種轉換規則,所以它是錯誤的:

    //錯誤:需要用戶定義的兩種轉換: // (1)把“9-999-99999-9”C式字符串字面量轉換成string // (2)再把這個(臨時的) string轉換成Sales_data item.combine("9-999-99999-9");

    如果我們想完成上述調用,可以顯式地把字符串轉換成string或者Sales_data對象:

    //正確:顯式地轉換成string,隱式地轉換成Sales_data item.combine(string("9-999-99999-9"));//正確:隱式地轉換成string,顯式地轉換成Sales_data item.combine(Sales_data("9-999-99999-9"));

    類類型轉換不是總有效

    是否需要從string到 Sales_data的轉換依賴于我們對用戶使用該轉換的看法。在此例中,這種轉換可能是對的。null_book中的string可能表示了一個不存在的ISBN編號。


    另一個是從istream到Sales_data的轉換:

    //使用istream構造函數創建一個函數傳遞給combine item.combine(cin);

    這段代碼隱式地把cin轉換成Sales_data,這個轉換執行了接受一個 istream 的Sales_data構造函數。該構造函數通過讀取標準輸入創建了一個(臨時的)Sales_data對象,隨后將得到的對象傳遞給combine。

    Sales_data對象是個臨時量(第2章內容),一旦 combine完成我們就不能再訪問它了。實際上,我們構建了一個對象,先將它的值加到item中,隨后將其丟棄。

    explicit抑制構造函數定義的隱式轉換

    在要求隱式轉換的程序上下文中,我們可以通過將構造函數聲明為explicit 加以阻止:

    class Sales_data { public:Sales_data() = default;Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }explicit Sales_data(const std::string &s): bookNo(s) { }explicit Sales_data(std::istream&);// remaining members as before };

    此時,沒有任何構造函數能用于隱式地創建Sales_data對象,之前的兩種用法都無法通過編譯:

    item.combine(null_book); // error: string constructor is explicit item.combine(cin); // error: istream constructor is explicit

    關鍵字explicit只對一個實參的構造函數有效。需要多個實參的構造函數不能用于執行隱式轉換,所以無須將這些構造函數指定為explicit的。

    只能在類內聲明構造函數時使用explicit關鍵字,在類外部定義時不應重復:

    // error: explicit allowed only on a constructor declaration in a class header explicit Sales_data::Sales_data(istream& is) {read(is, *this); }

    explicit
    英 [?k?spl?s?t] 美 [?k?spl?s?t]
    adj. 清楚明白的;易于理解的;(說話)清晰的,明確的;直言的;坦率的;直截了當的;不隱晦的;不含糊的

    explicit構造函數只能用于直接初始化,不能用于拷貝初始化

    發生隱式轉換的一種情況是當我們執行拷貝形式的初始化時(使用=)。此時,我們只能使用直接初始化而不能使用explicit構造函數:

    Sales_data item1(nul1_book);//正確:直接初始化 //錯誤:不能將explicit構造函數用于拷貝形式的初始化過程 Sales_data item2 = null_book;

    當我們用 explicit關鍵字聲明構造函數時,它將只能以直接初始化的形式使用。而且,編譯器將不會在自動轉換過程中使用該構造函數。


    如果使用等號(=)初始化一個變量,實際上執行的是拷貝初始化(copy initialization),編譯器把等號右側的初始值拷貝到新創建的對象中去。

    與之相反,如果不使用等號,則執行的是直接初始化(direct initialization)。

    (來自第3章)

    為轉換顯示地使用構造函數(可忽視explicit)

    盡管編譯器不會將 explicit 的構造函數用于隱式轉換過程,但是我們可以使用這樣的構造函數顯式地強制進行轉換

    //正確:實參是一個顯式構造的Sales_data對象 item.combine(Sales_data(null_book)); //正確: static_cast可以使用explicit的構造函數 item.combine(static_cast<Sales_data>(cin)) ;

    在第一個調用中,我們直接使用Sales_data的構造函數,該調用通過接受string的構造函數創建了一個臨時的Sales_data對象。

    在第二個調用中,我們使用static_cast (第4章內容)執行了顯式的而非隱式的轉換。其中,static_cast 使用istream構造函數創建了一個臨時的Sales_data對象。

    標準庫中含有顯式構造函數的類

    我們用過的一些標準庫中的類含有單參數的構造函數:

    • 接受一個單參數的const char*的string構造函數不是explicit的。
    • 接受一個容量參數的vector構造函數是explicit的。

    (兩個都是第3章內容)

    聚合類

    聚合類(aggregate class)使得用戶可以直接訪問其成員,并且具有特殊的初始化語法形式。當一個類滿足如下條件時,我們說它是聚合的:

    • 所有成員都是public的。
    • 沒有定義任何構造函數。
    • 沒有類內初始值。
    • 沒有基類,也沒有virtual函數,關于這部分知將在第15章詳細介紹。

    例如,下面的類是一個聚合類:

    struct Data {int ival;string s; };

    我們可以提供一個花括號括起來的成員初始值列表,并用它初始化聚合類的數據成員:

    //val1.ival = 0; val1.s = string ( "Anna") Data val1 = {0, "Anna"};

    初始值的順序必須與聲明的順序一致,也就是說,第一個成員的初始值要放在第一個,然后是第二個,以此類推。

    下面的例子是錯誤的

    //錯誤:不能使用"Anna"初始化ival,也不能使用1024初始化s Data val2 = { "Anna", 1024};

    與初始化數組元素的規則(第3章內容)一樣,如果初始值列表中的元素個數少于類的成員數量,則靠后的成員被值初始化(第3章內容)。初始值列表的元素個數絕對不能超過類的成員數量。

    值得注意的是,顯式地初始化類的對象的成員存在三個明顯的缺點

    • 要求類的所有成員都是public的。
    • 將正確初始化每個對象的每個成員的重任交給了類的用戶(而非類的作者)。因為用戶很容易忘掉某個初始值,或者提供一個不恰當的初始值,所以這樣的初始化過程冗長乏味且容易出錯。
    • 添加或刪除一個成員之后,所有的初始化語句都需要更新。

    字面值常量類

    在第6章中提到過constexpr函數的參數返回值必須是字面值類型。

    除了算術類型、引用和指針外,某些類也是字面值類型。和其他類不同,字面值類型的類可能含有constexpr函數成員。這樣的成員必須符合constexpr函數的所有要求,它們是隱式const的。

    數據成員都是字面值類型的聚合類是字面值常量類。如果一個類不是聚合類,但它符合下述要求,則它也是一個字面值常量類:

    • 數據成員都必須是字面值類型。
    • 類必須至少含有一個constexpr構造函數。
    • 如果一個數據成員含有類內初始值,則內置類型成員的初始值必須是一條常量表達式(第2章內容);或者如果成員屬于某種類類型,則初始值必須使用成員自己的constexpr構造函數。
    • 類必須使用析構函數的默認定義,該成員負責銷毀類的對象。

    constexpr構造函數

    盡管構造函數不能是const 的,但是字面值常量類的構造函數可以是constexpr函數。事實上,一個字面值常量類必須至少提供一個constexpr構造函數。

    不同于其他成員函數,構造函數不能被聲明成const的。當我們創建類的一個const對象時,直到構造函數完成初始化過程,對象才能真正取得其“常量”屬性。因此,構造函數在const對象的構造過程中可以向其寫值。(本章構造函數內容)

    constexpr函數(constexpr function)是指能用于常量表達式的函數。(第6章內容)

    constexpr構造函數可以聲明成=default的形式(或者是刪除函數的形式,第13章內容)。另外,constexpr構造函數必須既符合構造函數的要求(意味著不能包含返回語句),又符合constexpr函數的要求(意味著它能擁有的唯一可執行語句就是返回語句,第6章內容)。Otherwise, a constexpr constructor must meet the requirements of a constructor—meaning it can have no return statement—and of a constexpr function—meaning the only executable statement it can have is a return statement.

    綜合這兩點可知,constexpr構造函數體一般來說應該是空的。

    我們通過前置關鍵字constexpr就可以聲明一個constexpr構造函數了:

    class Debug { public:constexpr Debug(bool b = true): hw(b), io(b), other(b) {}constexpr Debug(bool h, bool i, bool o):hw(h), io(i), other(o) {}constexpr bool any() { return hw || io || other; }void set_io(bool b) { io = b; }void set_hw(bool b) { hw = b; }void set_other(bool b) { hw = b; } private:bool hw; // hardware errors other than IO errorsbool io; // IO errorsbool other; // other errors };

    constexpr構造函數必須初始化所有數據成員,初始值或者使用constexpr構造函數,或者是一條常量表達式。

    constexpr構造函數用于生成constexpr對象以及constexpr函數的參數或返回類型:

    constexpr Debug io_sub(false, true, false); // debugging IO if (io_sub.any()) // equivalent to if(true)cerr << "print appropriate error messages" << endl;constexpr Debug prod(false); // no debugging during production if (prod.any()) // equivalent to if(false)cerr << "print an error message" << endl;

    constexpr函數被隱式地指定為內聯函數,內聯函數可避免函數調用的開銷。(第6章內容)

    類的靜態成員

    有時,類需要它的一些成員與類本身直接相關,而不是與類的各個對象保持關聯。例如,一個銀行賬戶類可能需要一個數據成員來表示當前的基準利率。在此例中,我們希望利率與類關聯,而非與類的每個對象關聯。從實現效率的角度來看,沒必要每個對象都存儲利率信息。而且更加重要的是,一旦利率浮動,我們希望所有的對象都能使用新值。

    (MyNote:個人來理解:類的靜態成員指同一類的所有對象共享的成員。)

    聲明靜態成員

    我們通過在成員的聲明之前加上關鍵字static使得其與類關聯在一起。和其他成員一樣,靜態成員可以是public的或private的。靜態數據成員的類型可以是常量、引用、指針、類類型等。

    舉個例子,我們定義一個類,用它表示銀行的賬戶記錄:

    class Account { public:void calculate() { amount += amount * interestRate; }static double rate(){ return interestRate; }static void rate(double); private:std::string owner;double amount;static double interestRate;static double initRate(); };

    類的靜態成員存在于任何對象之外,對象中不包含任何與靜態數據成員有關的數據。因此,

    • 每個Account對象將包含兩個數據成員:owner和 amount。

    • 只存在一個interestRate對象而且它被所有Account對象共享。

    類似的,靜態成員函數也不與任何對象綁定在一起,它們不包含this指針。作為結果,靜態成員函數不能聲明成const的,而且我們也不能在static函數體內使用this指針。這一限制既適用于this的顯式使用,也對調用非靜態成員的隱式使用有效。

    使用類的靜態成員

    我們使用作用域運算符直接訪問靜態成員:

    double r; r = Account::rate(); //使用作用域運算符訪問靜態成員

    雖然靜態成員不屬于類的某個對象,但是我們仍然可以使用類的對象、引用或者指針來訪問靜態成員:

    Account ac1 ; Account *ac2 = &acl ; //調用靜態成員函數rate的等價形式r= acl.rate() ;//通過Account的對象或引用 r=ac2->rate();//通過指向Account對象的指針

    成員函數不用通過作用域運算符就能直接使用靜態成員:

    class Account { public:void calculate() { amount += amount * interestRate; } private:static double interestRate;//其他成員與之前的版本一致 };

    定義靜態成員

    和其他的成員函數一樣,我們既可以在類的內部也可以在類的外部定義靜態成員函數。當在類的外部定義靜態成員時,不能重復static關鍵字,該關鍵字只出現在類內部的聲明語句:

    void Account::rate(double newRate){interestRate = newRate; }

    Note:和類的所有成員一樣,當我們指向類外部的靜態成員時,必須指明成員所屬的類名。static關鍵字則只出現在類內部的聲明語句中。

    因為靜態數據成員不屬于類的任何一個對象,所以它們并不是在創建類的對象時被定義的。這意味著它們不是由類的構造函數初始化的。而且一般來說,我們不能在類的內部初始化靜態成員。相反的,必須在類的外部定義和初始化每個靜態成員。和其他對象一樣,一個靜態數據成員只能定義一次。

    類似于全局變量(第6章內容),靜態數據成員定義在任何函數之外。因此一旦它被定義,就將一直存在于程序的整個生命周期中。

    我們定義靜態數據成員的方式和在類的外部定義成員函數差不多。我們需要指定對象的類型名,然后是類名、作用域運算符以及成員自己的名字:

    //定義并初始化一個靜態成員 double Account::interestRate = initRate();

    這條語句定義了名為interestRate的對象,該對象是類Account的靜態成員,其類型是double。從類名開始,這條定義語句的剩余部分就都位于類的作用域之內了。因此,我們可以直接使用initRate函數。

    注意,雖然initRate是私有的,我們也能用它初始化interestRate。和其他成員的定義一樣,interestRate的定義也可以訪問類的私有成員。

    Tip:要想確保對象只定義一次,最好的辦法是把靜態數據成員的定義與其他非內聯函數的定義放在同一個文件中。

    靜態成員的類內初始化

    通常情況下,類的靜態成員不應該在類的內部初始化。然而,我們可以為靜態成員提供const整數類型的類內初始值,不過要求靜態成員必須是字面值常量類型的constexpr(MyNote:前提)。

    初始值必須是常量表達式,因為這些成員本身就是常量表達式,所以它們能用在所有適合于常量表達式的地方。例如,我們可以用一個初始化了的靜態數據成員指定數組成員的維度:

    class Account { public:static double rate() { return interestRate; }static void rate(double); private:static constexpr int period = 30;// period is a constant expressiondouble daily_tbl[period]; };

    如果某個靜態成員的應用場景僅限于編譯器可以替換它的值的情況,則一個初始化的const或constexpr static不需要分別定義。相反,如果我們將它用于值不能替換的場景中,則該成員必須有一條定義語句。

    例如,如果period的唯一用途就是定義daily_tbl的維度,則不需要在Account外面專門定義period。此時,如果我們忽略了這條定義,那么對程序非常微小的改動也可能造成編譯錯誤,因為程序找不到該成員的定義語句。舉個例子,當需要把Account::period傳遞給一個接受const int&的函數時,必須定義period。

    如果在類的內部提供了一個初始值,則成員的定義不能再指定一個初始值了:

    //一個不帶初始值的靜態成員的定義 constexpr int Account::period; //初始值在類的定義內提供

    Best Practices:即使一個常量靜態數據成員在類內部被初始化了,通常情況下也應該在類的外部定義一下該成員。

    靜態成員能用于某些場景,而普通成員不能

    如我們所見,靜態成員獨立于任何對象。因此,在某些非靜態數據成員可能非法的場合,靜態成員卻可以正常地使用。舉個例子,靜態數據成員可以是不完全類型(指先聲明,暫時不定義,本章“類類型內容”)。特別的,靜態數據成員的類型可以就是它所屬的類類型。而非靜態數據成員則受到限制,只能聲明成它所屬類的指針或引用

    class Bar { public:// ... private:static Bar meml;//正確:靜態成員可以是不完全類型Bar *mem2 ;//正確:指針成員可以是不完全類型Bar mem3 ;//錯誤:數據成員必須是完全類型 };

    靜態成員和普通成員的另外一個區別是我們可以使用靜態成員作為默認實參:

    class Screen { public://bkground表示一個在類中稍后定義的靜態成員Screen& clear(char = bkground) ; private:static const char bkground; };

    非靜態數據成員不能作為默認實參,因為它的值本身屬于對象的一部分,這么做的結果是無法真正提供一個對象以便從中獲取成員的值,最終將引發錯誤。

    一些術語

    類(class)C++提供的自定義數據類型的機制。類可以包含數據、函數和類型成員。一個類定義一種新的類型和一個新的作用域。

    總結

    以上是生活随笔為你收集整理的《C++ Primer 5th》笔记(7 / 19):类的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    亚洲s色大片在线观看 | 男女超爽视频免费播放 | 亚洲精品一区二区三区大桥未久 | 国产午夜视频在线观看 | 亚洲gv猛男gv无码男同 | 精品熟女少妇av免费观看 | 精品国产精品久久一区免费式 | 大屁股大乳丰满人妻 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 日韩少妇内射免费播放 | 国产精品爱久久久久久久 | 亚洲色大成网站www | 久青草影院在线观看国产 | 中文字幕人妻丝袜二区 | 亚洲 另类 在线 欧美 制服 | 亚洲日韩精品欧美一区二区 | 亚洲а∨天堂久久精品2021 | 精品久久久无码人妻字幂 | 丰满少妇熟乱xxxxx视频 | 国产内射老熟女aaaa | 狂野欧美激情性xxxx | www国产亚洲精品久久网站 | 5858s亚洲色大成网站www | 亚洲精品综合一区二区三区在线 | 中文字幕无码热在线视频 | 性欧美熟妇videofreesex | 久久久久免费精品国产 | 亚洲无人区一区二区三区 | 少妇厨房愉情理9仑片视频 | 性啪啪chinese东北女人 | 色欲av亚洲一区无码少妇 | 丰满少妇人妻久久久久久 | 人妻有码中文字幕在线 | 精品国产青草久久久久福利 | 美女极度色诱视频国产 | 久久精品视频在线看15 | 天堂亚洲免费视频 | 国产成人午夜福利在线播放 | 亚洲精品国产精品乱码视色 | 亚洲国产精品无码一区二区三区 | 日韩人妻少妇一区二区三区 | 俄罗斯老熟妇色xxxx | 无遮无挡爽爽免费视频 | 精品熟女少妇av免费观看 | 日日摸天天摸爽爽狠狠97 | 九九在线中文字幕无码 | 亚洲 欧美 激情 小说 另类 | 永久黄网站色视频免费直播 | 欧美午夜特黄aaaaaa片 | 亚洲精品午夜国产va久久成人 | 国产sm调教视频在线观看 | 欧美怡红院免费全部视频 | 67194成是人免费无码 | 国产香蕉97碰碰久久人人 | 欧美色就是色 | 久久精品国产日本波多野结衣 | 狠狠色噜噜狠狠狠狠7777米奇 | 久久亚洲精品中文字幕无男同 | 强辱丰满人妻hd中文字幕 | 国产精品二区一区二区aⅴ污介绍 | 国产艳妇av在线观看果冻传媒 | 久久99精品久久久久久动态图 | 人妻少妇精品视频专区 | 国产精品二区一区二区aⅴ污介绍 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 丰满少妇高潮惨叫视频 | 国产超级va在线观看视频 | 亚洲精品国产品国语在线观看 | 乱码av麻豆丝袜熟女系列 | 欧美亚洲国产一区二区三区 | 国产欧美精品一区二区三区 | 美女毛片一区二区三区四区 | 成人一区二区免费视频 | 日日噜噜噜噜夜夜爽亚洲精品 | 3d动漫精品啪啪一区二区中 | 人妻插b视频一区二区三区 | 国内少妇偷人精品视频 | 亚洲国产精品无码一区二区三区 | 中文字幕色婷婷在线视频 | 久9re热视频这里只有精品 | 国产亚洲精品久久久ai换 | 蜜桃av抽搐高潮一区二区 | 熟女少妇在线视频播放 | 久久久国产精品无码免费专区 | 日本精品人妻无码免费大全 | 亚洲精品无码人妻无码 | 日韩在线不卡免费视频一区 | 亚洲第一网站男人都懂 | 亚洲精品一区二区三区大桥未久 | 亚洲成色www久久网站 | 国产农村乱对白刺激视频 | 人妻互换免费中文字幕 | 中文字幕精品av一区二区五区 | 学生妹亚洲一区二区 | 国产精品香蕉在线观看 | 荫蒂添的好舒服视频囗交 | 一个人看的www免费视频在线观看 | 人人爽人人澡人人人妻 | av香港经典三级级 在线 | 伊人久久大香线蕉亚洲 | 成人精品天堂一区二区三区 | 18黄暴禁片在线观看 | 高清不卡一区二区三区 | 99视频精品全部免费免费观看 | 亚洲欧美中文字幕5发布 | 国产av剧情md精品麻豆 | 在线a亚洲视频播放在线观看 | 日本在线高清不卡免费播放 | 亚洲娇小与黑人巨大交 | 日本一区二区三区免费高清 | 久久无码中文字幕免费影院蜜桃 | 国产精品内射视频免费 | 狠狠色欧美亚洲狠狠色www | 国产精品-区区久久久狼 | 国产成人午夜福利在线播放 | 东京一本一道一二三区 | 精品夜夜澡人妻无码av蜜桃 | 色五月丁香五月综合五月 | 成人欧美一区二区三区黑人免费 | 精品久久久中文字幕人妻 | 又粗又大又硬又长又爽 | 无码人妻黑人中文字幕 | 国产精品无码永久免费888 | 日日鲁鲁鲁夜夜爽爽狠狠 | 国产亚洲精品久久久久久久 | 少妇被黑人到高潮喷出白浆 | 中文字幕无码av激情不卡 | 国产精品久久久午夜夜伦鲁鲁 | 国产凸凹视频一区二区 | 人妻少妇精品视频专区 | 最新国产麻豆aⅴ精品无码 | 欧美日本日韩 | 成熟人妻av无码专区 | 一区二区三区高清视频一 | 成人精品视频一区二区三区尤物 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 一本加勒比波多野结衣 | 国产办公室秘书无码精品99 | 99久久99久久免费精品蜜桃 | 欧美精品一区二区精品久久 | 色五月丁香五月综合五月 | 久久久精品国产sm最大网站 | 一本大道久久东京热无码av | 国产色xx群视频射精 | 欧美日韩一区二区三区自拍 | 亚洲色偷偷偷综合网 | 亚洲日韩av一区二区三区中文 | 啦啦啦www在线观看免费视频 | 亚洲午夜久久久影院 | 国产精品.xx视频.xxtv | 国产亚洲欧美在线专区 | 国产猛烈高潮尖叫视频免费 | 亚洲精品一区二区三区大桥未久 | 欧美性生交活xxxxxdddd | 国产内射爽爽大片视频社区在线 | 一本色道久久综合亚洲精品不卡 | 欧美性色19p | 色综合视频一区二区三区 | 狠狠色欧美亚洲狠狠色www | 在线亚洲高清揄拍自拍一品区 | 丰满岳乱妇在线观看中字无码 | 国内精品一区二区三区不卡 | 亚洲成av人综合在线观看 | 中文字幕无码日韩专区 | 日韩精品久久久肉伦网站 | 亚洲乱码日产精品bd | 亚洲国产精品一区二区第一页 | 成人无码视频在线观看网站 | 中文字幕无码人妻少妇免费 | 国产高潮视频在线观看 | 久久亚洲国产成人精品性色 | 丰满护士巨好爽好大乳 | 国产成人精品视频ⅴa片软件竹菊 | 在线亚洲高清揄拍自拍一品区 | 久久国语露脸国产精品电影 | 色一情一乱一伦 | 欧美熟妇另类久久久久久不卡 | 欧美丰满熟妇xxxx | 成在人线av无码免观看麻豆 | 成人亚洲精品久久久久 | 老熟妇乱子伦牲交视频 | 中文字幕av无码一区二区三区电影 | 精品无人区无码乱码毛片国产 | 俺去俺来也www色官网 | 亚洲s码欧洲m码国产av | www国产亚洲精品久久网站 | 亚洲国产精品成人久久蜜臀 | 97久久超碰中文字幕 | 扒开双腿吃奶呻吟做受视频 | 久久婷婷五月综合色国产香蕉 | 无人区乱码一区二区三区 | 国产精品久久久一区二区三区 | 小sao货水好多真紧h无码视频 | аⅴ资源天堂资源库在线 | 老头边吃奶边弄进去呻吟 | 97久久国产亚洲精品超碰热 | 特黄特色大片免费播放器图片 | 免费播放一区二区三区 | 国产精品久免费的黄网站 | 国产高清不卡无码视频 | 日日躁夜夜躁狠狠躁 | 亚洲色无码一区二区三区 | 中文字幕人妻无码一区二区三区 | 小sao货水好多真紧h无码视频 | 欧美熟妇另类久久久久久不卡 | 成人免费视频在线观看 | 澳门永久av免费网站 | 国产精品美女久久久久av爽李琼 | 四虎国产精品免费久久 | 亚洲爆乳精品无码一区二区三区 | 日韩人妻无码一区二区三区久久99 | aⅴ亚洲 日韩 色 图网站 播放 | 中国大陆精品视频xxxx | 亚洲中文字幕无码中文字在线 | 国产性生交xxxxx无码 | 成熟妇人a片免费看网站 | 国产成人一区二区三区在线观看 | 日韩欧美成人免费观看 | 国产成人久久精品流白浆 | 国产亚洲视频中文字幕97精品 | 精品一二三区久久aaa片 | 亚拍精品一区二区三区探花 | 精品人妻中文字幕有码在线 | 男女性色大片免费网站 | 国产极品视觉盛宴 | 色婷婷欧美在线播放内射 | 国产人成高清在线视频99最全资源 | 成人免费无码大片a毛片 | 老熟妇乱子伦牲交视频 | 色诱久久久久综合网ywww | 永久免费观看国产裸体美女 | 亚洲中文字幕成人无码 | 麻花豆传媒剧国产免费mv在线 | 久久精品国产精品国产精品污 | 欧美亚洲国产一区二区三区 | aⅴ亚洲 日韩 色 图网站 播放 | 娇妻被黑人粗大高潮白浆 | 国产真实乱对白精彩久久 | 久久aⅴ免费观看 | 亚洲 另类 在线 欧美 制服 | 欧美激情内射喷水高潮 | 日本xxxx色视频在线观看免费 | 熟妇激情内射com | 亚洲精品国偷拍自产在线观看蜜桃 | a国产一区二区免费入口 | 日本一区二区三区免费高清 | 日韩欧美中文字幕在线三区 | 国产精品第一国产精品 | 玩弄少妇高潮ⅹxxxyw | 色欲人妻aaaaaaa无码 | 学生妹亚洲一区二区 | 国产激情综合五月久久 | 欧美变态另类xxxx | 午夜福利不卡在线视频 | 国产激情无码一区二区 | 亚洲熟妇色xxxxx亚洲 | 自拍偷自拍亚洲精品被多人伦好爽 | 人人澡人人妻人人爽人人蜜桃 | 红桃av一区二区三区在线无码av | 国产成人精品视频ⅴa片软件竹菊 | 四虎影视成人永久免费观看视频 | 99久久无码一区人妻 | 国产高潮视频在线观看 | 欧洲熟妇精品视频 | 又大又黄又粗又爽的免费视频 | 国产亚洲精品久久久闺蜜 | 国产成人综合在线女婷五月99播放 | 色五月丁香五月综合五月 | 熟女少妇人妻中文字幕 | 欧美自拍另类欧美综合图片区 | 国产精品99久久精品爆乳 | 亚洲中文字幕乱码av波多ji | 精品久久久久久亚洲精品 | 亚洲精品成人av在线 | 精品国产aⅴ无码一区二区 | 成人毛片一区二区 | 99久久久无码国产aaa精品 | 亚洲精品成人av在线 | 久久国语露脸国产精品电影 | 欧美自拍另类欧美综合图片区 | 正在播放东北夫妻内射 | 狠狠综合久久久久综合网 | 欧美丰满熟妇xxxx | 无码人妻丰满熟妇区五十路百度 | 日本成熟视频免费视频 | 国产xxx69麻豆国语对白 | 亚洲日韩乱码中文无码蜜桃臀网站 | 人人爽人人爽人人片av亚洲 | 久久99精品国产.久久久久 | 蜜桃视频插满18在线观看 | 久久 国产 尿 小便 嘘嘘 | 国产精品欧美成人 | 亚洲熟妇自偷自拍另类 | 国产精品高潮呻吟av久久4虎 | 亚洲午夜无码久久 | 亚洲国产精品久久久久久 | 日韩av激情在线观看 | 久久久久免费看成人影片 | 性做久久久久久久久 | 国产精品毛多多水多 | 亚洲日本va午夜在线电影 | 99久久无码一区人妻 | 亚洲成av人片在线观看无码不卡 | 色婷婷欧美在线播放内射 | 国产亚洲视频中文字幕97精品 | 日韩欧美群交p片內射中文 | 无码一区二区三区在线观看 | 一区二区三区高清视频一 | 丰满诱人的人妻3 | 日韩精品a片一区二区三区妖精 | 撕开奶罩揉吮奶头视频 | 激情内射亚州一区二区三区爱妻 | 日本一本二本三区免费 | 18禁黄网站男男禁片免费观看 | 99久久99久久免费精品蜜桃 | 狠狠色噜噜狠狠狠狠7777米奇 | 国产午夜精品一区二区三区嫩草 | 无码人妻av免费一区二区三区 | 人妻天天爽夜夜爽一区二区 | 亚洲中文字幕乱码av波多ji | 国产成人精品无码播放 | 日本大香伊一区二区三区 | 欧美猛少妇色xxxxx | 久久aⅴ免费观看 | 成人精品一区二区三区中文字幕 | av在线亚洲欧洲日产一区二区 | 精品偷自拍另类在线观看 | 亚洲精品久久久久久一区二区 | 黑人巨大精品欧美黑寡妇 | 日韩成人一区二区三区在线观看 | 日韩精品无码一本二本三本色 | а√资源新版在线天堂 | 国产另类ts人妖一区二区 | 九九久久精品国产免费看小说 | 成熟人妻av无码专区 | 午夜精品久久久内射近拍高清 | 扒开双腿吃奶呻吟做受视频 | 亚洲色成人中文字幕网站 | 小泽玛莉亚一区二区视频在线 | 亚洲精品一区三区三区在线观看 | 精品午夜福利在线观看 | 真人与拘做受免费视频 | 日韩欧美群交p片內射中文 | 九九综合va免费看 | 国产高潮视频在线观看 | 又大又硬又爽免费视频 | 国产成人精品视频ⅴa片软件竹菊 | 无码人妻丰满熟妇区五十路百度 | 色诱久久久久综合网ywww | 99久久无码一区人妻 | 欧洲熟妇精品视频 | 成人免费视频视频在线观看 免费 | 亚洲国产欧美国产综合一区 | 激情五月综合色婷婷一区二区 | 日韩成人一区二区三区在线观看 | 人人妻人人澡人人爽欧美一区 | 无码吃奶揉捏奶头高潮视频 | 国产精品久久精品三级 | 97夜夜澡人人双人人人喊 | 精品国产一区二区三区四区 | 亚洲精品成人福利网站 | 亚洲国产精品美女久久久久 | 婷婷色婷婷开心五月四房播播 | 福利一区二区三区视频在线观看 | 国产精品久久久久久无码 | 欧美丰满老熟妇xxxxx性 | 精品 日韩 国产 欧美 视频 | 人人妻人人澡人人爽欧美一区九九 | 亚洲综合在线一区二区三区 | 国产高清av在线播放 | 蜜臀aⅴ国产精品久久久国产老师 | 国产舌乚八伦偷品w中 | 午夜肉伦伦影院 | 性色欲网站人妻丰满中文久久不卡 | 国产麻豆精品一区二区三区v视界 | 成人性做爰aaa片免费看 | 国产偷抇久久精品a片69 | 中文字幕日产无线码一区 | 日本xxxx色视频在线观看免费 | 88国产精品欧美一区二区三区 | 亚洲国产精品久久人人爱 | 综合激情五月综合激情五月激情1 | 精品一区二区三区无码免费视频 | 国内少妇偷人精品视频 | 搡女人真爽免费视频大全 | 好屌草这里只有精品 | 免费无码午夜福利片69 | 国产欧美精品一区二区三区 | 黑人巨大精品欧美一区二区 | 一区二区三区乱码在线 | 欧洲 | 久久综合久久自在自线精品自 | 日日躁夜夜躁狠狠躁 | 亚洲日韩精品欧美一区二区 | 99久久久无码国产aaa精品 | 久久精品丝袜高跟鞋 | 乱中年女人伦av三区 | 国产片av国语在线观看 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 国产精品爱久久久久久久 | 婷婷五月综合缴情在线视频 | 少妇无码av无码专区在线观看 | 日本成熟视频免费视频 | 嫩b人妻精品一区二区三区 | 久久精品无码一区二区三区 | 精品国产aⅴ无码一区二区 | 免费无码的av片在线观看 | 98国产精品综合一区二区三区 | 欧美性生交xxxxx久久久 | 国内精品九九久久久精品 | 成 人 免费观看网站 | 高潮喷水的毛片 | 国产人妻人伦精品 | 色婷婷综合激情综在线播放 | 激情国产av做激情国产爱 | 亚洲 欧美 激情 小说 另类 | 国产舌乚八伦偷品w中 | 国产99久久精品一区二区 | 欧美大屁股xxxxhd黑色 | 搡女人真爽免费视频大全 | 黑人粗大猛烈进出高潮视频 | 日本又色又爽又黄的a片18禁 | 女人色极品影院 | 欧美成人高清在线播放 | 亚洲区欧美区综合区自拍区 | 狠狠色欧美亚洲狠狠色www | 成 人影片 免费观看 | 国产 精品 自在自线 | 欧美怡红院免费全部视频 | 久久国产劲爆∧v内射 | 久久久久免费精品国产 | 国产精品久久久 | 国产成人无码av在线影院 | 欧美老妇与禽交 | 1000部啪啪未满十八勿入下载 | 老司机亚洲精品影院 | 天天躁夜夜躁狠狠是什么心态 | 超碰97人人做人人爱少妇 | 日韩精品乱码av一区二区 | 久久人人爽人人人人片 | av在线亚洲欧洲日产一区二区 | 美女黄网站人色视频免费国产 | 国产精品亚洲一区二区三区喷水 | 国产成人无码午夜视频在线观看 | 国产精品久久久久7777 | 日韩人妻少妇一区二区三区 | 无码人妻黑人中文字幕 | 中文字幕无码免费久久9一区9 | 又大又黄又粗又爽的免费视频 | 日日天干夜夜狠狠爱 | 亚洲の无码国产の无码步美 | 国内精品一区二区三区不卡 | 超碰97人人做人人爱少妇 | a在线亚洲男人的天堂 | 秋霞特色aa大片 | 亚洲精品综合一区二区三区在线 | 中文无码成人免费视频在线观看 | 麻豆精产国品 | 中文字幕日韩精品一区二区三区 | 国产69精品久久久久app下载 | 18精品久久久无码午夜福利 | 久久综合给合久久狠狠狠97色 | 天堂久久天堂av色综合 | 亚洲成av人片在线观看无码不卡 | 亚洲国精产品一二二线 | 亚洲毛片av日韩av无码 | 亚洲日本va午夜在线电影 | 国产明星裸体无码xxxx视频 | 亚洲国产精品成人久久蜜臀 | 国产特级毛片aaaaaa高潮流水 | 一本无码人妻在中文字幕免费 | 正在播放东北夫妻内射 | 国产精品久久久久无码av色戒 | 又粗又大又硬又长又爽 | 国产无遮挡又黄又爽免费视频 | 曰本女人与公拘交酡免费视频 | 人人妻人人藻人人爽欧美一区 | 激情内射亚州一区二区三区爱妻 | 夜夜夜高潮夜夜爽夜夜爰爰 | 18禁黄网站男男禁片免费观看 | 欧美喷潮久久久xxxxx | 麻豆国产人妻欲求不满谁演的 | 国产成人精品无码播放 | 国产香蕉尹人视频在线 | 国产在线无码精品电影网 | 99久久婷婷国产综合精品青草免费 | 日本va欧美va欧美va精品 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 无码人妻av免费一区二区三区 | 久久99精品久久久久久 | 国产在线精品一区二区三区直播 | 国产人妖乱国产精品人妖 | 国内精品一区二区三区不卡 | 久久国产精品二国产精品 | 精品人妻中文字幕有码在线 | 精品久久久中文字幕人妻 | 国产福利视频一区二区 | 欧美人妻一区二区三区 | 啦啦啦www在线观看免费视频 | 国产深夜福利视频在线 | 国产人妻精品一区二区三区不卡 | 一本无码人妻在中文字幕免费 | 乱人伦人妻中文字幕无码久久网 | 激情人妻另类人妻伦 | 色五月丁香五月综合五月 | 国内精品人妻无码久久久影院 | 真人与拘做受免费视频 | 红桃av一区二区三区在线无码av | √8天堂资源地址中文在线 | 在线欧美精品一区二区三区 | 久久亚洲日韩精品一区二区三区 | 欧洲精品码一区二区三区免费看 | 国产日产欧产精品精品app | 国产成人久久精品流白浆 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 玩弄中年熟妇正在播放 | 欧美猛少妇色xxxxx | 2020久久超碰国产精品最新 | 无码av免费一区二区三区试看 | 丝袜人妻一区二区三区 | 中国女人内谢69xxxxxa片 | 男人和女人高潮免费网站 | 亚洲国产精品无码一区二区三区 | 丰满少妇熟乱xxxxx视频 | 国产精品自产拍在线观看 | 久久国产36精品色熟妇 | 内射爽无广熟女亚洲 | 亚洲精品国偷拍自产在线麻豆 | 乱码av麻豆丝袜熟女系列 | 国产成人综合在线女婷五月99播放 | 亚洲日韩av片在线观看 | 国产精品久久久久9999小说 | 偷窥日本少妇撒尿chinese | 亚洲小说图区综合在线 | 国产国语老龄妇女a片 | 亚洲综合伊人久久大杳蕉 | 国产精品无码成人午夜电影 | 噜噜噜亚洲色成人网站 | 纯爱无遮挡h肉动漫在线播放 | 日韩人妻无码中文字幕视频 | 亚洲大尺度无码无码专区 | 久久国产精品偷任你爽任你 | 国产成人无码区免费内射一片色欲 | 欧美乱妇无乱码大黄a片 | 三级4级全黄60分钟 | 欧美野外疯狂做受xxxx高潮 | 精品国产国产综合精品 | 理论片87福利理论电影 | 亚洲爆乳精品无码一区二区三区 | 人人妻人人澡人人爽人人精品 | 无套内谢老熟女 | 精品偷拍一区二区三区在线看 | 日产精品99久久久久久 | 在线欧美精品一区二区三区 | 午夜肉伦伦影院 | 在线精品国产一区二区三区 | 性色av无码免费一区二区三区 | 国产在线精品一区二区三区直播 | 伊人色综合久久天天小片 | 亚洲精品成人福利网站 | 免费国产成人高清在线观看网站 | 久久人妻内射无码一区三区 | 亚洲娇小与黑人巨大交 | av在线亚洲欧洲日产一区二区 | 国产莉萝无码av在线播放 | 国产亚洲精品久久久ai换 | 人妻无码αv中文字幕久久琪琪布 | 帮老师解开蕾丝奶罩吸乳网站 | 女人被男人爽到呻吟的视频 | 国产精品高潮呻吟av久久 | 久久国内精品自在自线 | 人人妻人人澡人人爽欧美一区 | 免费国产成人高清在线观看网站 | 无码av最新清无码专区吞精 | 全黄性性激高免费视频 | 丰满岳乱妇在线观看中字无码 | 给我免费的视频在线观看 | 亚洲国产欧美日韩精品一区二区三区 | 人人爽人人爽人人片av亚洲 | 亚洲理论电影在线观看 | 国产精品沙发午睡系列 | 亚洲男人av天堂午夜在 | 国产va免费精品观看 | 欧美日韩人成综合在线播放 | 男女猛烈xx00免费视频试看 | 成熟人妻av无码专区 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 香蕉久久久久久av成人 | 欧美怡红院免费全部视频 | 中文毛片无遮挡高清免费 | 欧美人与牲动交xxxx | 老子影院午夜伦不卡 | 在线观看国产一区二区三区 | 熟妇女人妻丰满少妇中文字幕 | 日本丰满护士爆乳xxxx | 国产精品办公室沙发 | 国产亚洲视频中文字幕97精品 | 精品无码国产自产拍在线观看蜜 | 久久精品中文闷骚内射 | 一本久久a久久精品亚洲 | 天天av天天av天天透 | 国产99久久精品一区二区 | 免费人成在线观看网站 | 男女超爽视频免费播放 | 5858s亚洲色大成网站www | 国产精品永久免费视频 | 日韩欧美成人免费观看 | 色欲综合久久中文字幕网 | 四虎国产精品一区二区 | 俄罗斯老熟妇色xxxx | 欧美成人午夜精品久久久 | 老熟妇仑乱视频一区二区 | 欧美成人免费全部网站 | 久久久久久九九精品久 | 性生交片免费无码看人 | 国产亚洲精品久久久久久久 | 日本大乳高潮视频在线观看 | 久久精品国产精品国产精品污 | 人妻少妇被猛烈进入中文字幕 | 午夜精品一区二区三区在线观看 | 18禁黄网站男男禁片免费观看 | 丁香啪啪综合成人亚洲 | 国产内射爽爽大片视频社区在线 | 青草青草久热国产精品 | 桃花色综合影院 | 国产av久久久久精东av | 中文亚洲成a人片在线观看 | 久久国产精品精品国产色婷婷 | 欧美三级a做爰在线观看 | 久久久久亚洲精品男人的天堂 | 免费网站看v片在线18禁无码 | 国产亚洲美女精品久久久2020 | 午夜无码人妻av大片色欲 | 激情内射亚州一区二区三区爱妻 | 亚洲精品一区三区三区在线观看 | 国产人妻精品午夜福利免费 | 兔费看少妇性l交大片免费 | 在线视频网站www色 | 亚洲熟妇色xxxxx欧美老妇 | 国产片av国语在线观看 | 97久久精品无码一区二区 | 天堂久久天堂av色综合 | 日韩人妻少妇一区二区三区 | 日韩精品无码一区二区中文字幕 | yw尤物av无码国产在线观看 | 国产成人精品一区二区在线小狼 | 国产亚av手机在线观看 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 人人妻人人澡人人爽精品欧美 | 亚洲欧洲无卡二区视頻 | 中文亚洲成a人片在线观看 | 精品久久久中文字幕人妻 | 熟女俱乐部五十路六十路av | 久久精品女人的天堂av | 1000部夫妻午夜免费 | 少妇被粗大的猛进出69影院 | 亚洲欧美精品aaaaaa片 | 国产精品无码一区二区三区不卡 | 国内精品人妻无码久久久影院蜜桃 | 婷婷综合久久中文字幕蜜桃三电影 | 日韩成人一区二区三区在线观看 | 国产97人人超碰caoprom | 夜精品a片一区二区三区无码白浆 | 国产真人无遮挡作爱免费视频 | 无码午夜成人1000部免费视频 | 亚洲精品中文字幕久久久久 | 无码成人精品区在线观看 | 国产女主播喷水视频在线观看 | av人摸人人人澡人人超碰下载 | 欧美人与禽zoz0性伦交 | 久久99精品久久久久久动态图 | 精品欧洲av无码一区二区三区 | 久久综合狠狠综合久久综合88 | 东京热无码av男人的天堂 | 久久久久久av无码免费看大片 | 国产艳妇av在线观看果冻传媒 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 欧美激情一区二区三区成人 | 少女韩国电视剧在线观看完整 | 日韩精品一区二区av在线 | 亚洲成av人影院在线观看 | 国产成人精品久久亚洲高清不卡 | 玩弄人妻少妇500系列视频 | 亲嘴扒胸摸屁股激烈网站 | 久久精品国产亚洲精品 | 人人爽人人爽人人片av亚洲 | 国产乱人偷精品人妻a片 | 成熟女人特级毛片www免费 | 波多野结衣 黑人 | 亚洲国产一区二区三区在线观看 | 欧美人与禽猛交狂配 | 波多野42部无码喷潮在线 | 一本大道久久东京热无码av | 久久精品中文字幕大胸 | 精品 日韩 国产 欧美 视频 | 久久99精品国产麻豆蜜芽 | 一本久久a久久精品vr综合 | 人妻互换免费中文字幕 | 撕开奶罩揉吮奶头视频 | 国产精品久免费的黄网站 | 国产国产精品人在线视 | 亚洲熟妇自偷自拍另类 | 亚洲成a人片在线观看无码 | 亚洲va欧美va天堂v国产综合 | 国产肉丝袜在线观看 | 亚洲啪av永久无码精品放毛片 | 国产精品亚洲综合色区韩国 | 国产免费无码一区二区视频 | 动漫av一区二区在线观看 | 亚洲一区二区三区播放 | 亚洲 高清 成人 动漫 | 国产精品久久久久久亚洲毛片 | 国产午夜福利100集发布 | 久久国产精品偷任你爽任你 | 少妇被黑人到高潮喷出白浆 | 亚洲国产精品久久久久久 | 日韩少妇内射免费播放 | 丰满岳乱妇在线观看中字无码 | 久久久中文字幕日本无吗 | 国产精品久久久久久无码 | 久久zyz资源站无码中文动漫 | 亚洲人成人无码网www国产 | 久久久久se色偷偷亚洲精品av | 少妇性l交大片 | 亚洲日韩一区二区三区 | 国产精品久久久av久久久 | 日本又色又爽又黄的a片18禁 | 精品欧洲av无码一区二区三区 | 一二三四社区在线中文视频 | 日欧一片内射va在线影院 | 久久精品中文字幕一区 | 中文字幕无码热在线视频 | 午夜肉伦伦影院 | 精品一区二区三区无码免费视频 | 性欧美疯狂xxxxbbbb | 内射爽无广熟女亚洲 | 一本久久伊人热热精品中文字幕 | 搡女人真爽免费视频大全 | 日日天干夜夜狠狠爱 | 国产成人精品三级麻豆 | 久久久久se色偷偷亚洲精品av | 国产精品亚洲五月天高清 | 性做久久久久久久久 | 爽爽影院免费观看 | 亚洲乱码中文字幕在线 | 亚洲精品久久久久中文第一幕 | 欧美刺激性大交 | 国产成人久久精品流白浆 | 无码av最新清无码专区吞精 | 亚洲日韩精品欧美一区二区 | 熟妇人妻中文av无码 | 国产精华av午夜在线观看 | 国产精品久久国产三级国 | 午夜福利试看120秒体验区 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 波多野结衣高清一区二区三区 | 成熟人妻av无码专区 | 亚洲狠狠色丁香婷婷综合 | 国产精品香蕉在线观看 | 日韩av激情在线观看 | 中文无码成人免费视频在线观看 | 高潮毛片无遮挡高清免费 | 亚洲国产精华液网站w | 成人亚洲精品久久久久软件 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 日韩视频 中文字幕 视频一区 | 国产在线aaa片一区二区99 | 欧洲极品少妇 | 欧美丰满熟妇xxxx性ppx人交 | 日韩人妻无码中文字幕视频 | 少妇无套内谢久久久久 | 99久久婷婷国产综合精品青草免费 | 国产一区二区三区四区五区加勒比 | 2019午夜福利不卡片在线 | 久久99精品久久久久久 | 高清不卡一区二区三区 | 精品人妻中文字幕有码在线 | 99精品无人区乱码1区2区3区 | 丰满人妻一区二区三区免费视频 | 无码人妻精品一区二区三区不卡 | 久久国产自偷自偷免费一区调 | 婷婷丁香五月天综合东京热 | 又粗又大又硬毛片免费看 | 东京一本一道一二三区 | 精品乱子伦一区二区三区 | 中文字幕av伊人av无码av | 久久久国产一区二区三区 | 99久久婷婷国产综合精品青草免费 | 精品无码一区二区三区爱欲 | 中文毛片无遮挡高清免费 | 国内精品久久久久久中文字幕 | 免费男性肉肉影院 | 中文字幕乱码人妻无码久久 | 欧美日韩一区二区免费视频 | 国产97人人超碰caoprom | 无码人妻丰满熟妇区毛片18 | 又大又黄又粗又爽的免费视频 | 亚洲色在线无码国产精品不卡 | 欧洲熟妇色 欧美 | a国产一区二区免费入口 | 久久国产精品偷任你爽任你 | 亚欧洲精品在线视频免费观看 | 亚洲七七久久桃花影院 | 日本熟妇人妻xxxxx人hd | 最近的中文字幕在线看视频 | 亚洲综合精品香蕉久久网 | 国产人妻久久精品二区三区老狼 | 中国大陆精品视频xxxx | 色爱情人网站 | 亚洲毛片av日韩av无码 | 十八禁视频网站在线观看 | 日日夜夜撸啊撸 | 亚洲日本va午夜在线电影 | 婷婷六月久久综合丁香 | 午夜无码区在线观看 | 激情内射亚州一区二区三区爱妻 | 成人欧美一区二区三区黑人免费 | 国语精品一区二区三区 | 日日摸夜夜摸狠狠摸婷婷 | 在线亚洲高清揄拍自拍一品区 | 久久国产精品二国产精品 | √天堂资源地址中文在线 | 一本精品99久久精品77 | 丰满妇女强制高潮18xxxx | 日日噜噜噜噜夜夜爽亚洲精品 | 亚洲另类伦春色综合小说 | 内射巨臀欧美在线视频 | 国精品人妻无码一区二区三区蜜柚 | 亚洲精品中文字幕久久久久 | 内射爽无广熟女亚洲 | 国产激情无码一区二区app | 天天做天天爱天天爽综合网 | 麻豆av传媒蜜桃天美传媒 | 欧美日韩一区二区三区自拍 | 自拍偷自拍亚洲精品10p | 国产av人人夜夜澡人人爽麻豆 | 欧洲精品码一区二区三区免费看 | 亚洲精品成a人在线观看 | 成人aaa片一区国产精品 | 国产无套粉嫩白浆在线 | 亚洲乱码中文字幕在线 | 国产在线精品一区二区高清不卡 | 久久97精品久久久久久久不卡 | 亚洲国产精品无码久久久久高潮 | 亚洲日韩一区二区三区 | 国产明星裸体无码xxxx视频 | 国产人妻精品午夜福利免费 | 麻豆国产丝袜白领秘书在线观看 | 青草青草久热国产精品 | 欧美老妇与禽交 | 偷窥日本少妇撒尿chinese | 国产在热线精品视频 | 国产sm调教视频在线观看 | 永久免费观看美女裸体的网站 | 国产9 9在线 | 中文 | 丝袜人妻一区二区三区 | 无码av免费一区二区三区试看 | 日韩av无码一区二区三区 | 久久 国产 尿 小便 嘘嘘 | 伊在人天堂亚洲香蕉精品区 | 波多野结衣一区二区三区av免费 | 粉嫩少妇内射浓精videos | 亚洲区欧美区综合区自拍区 | 久久精品人妻少妇一区二区三区 | 国产舌乚八伦偷品w中 | 日韩精品无码一区二区中文字幕 | 啦啦啦www在线观看免费视频 | 国产亚洲精品久久久久久国模美 | 无码精品人妻一区二区三区av | 日欧一片内射va在线影院 | 激情五月综合色婷婷一区二区 | 精品人妻人人做人人爽夜夜爽 | 国产人妻精品一区二区三区 | 国产精品久久久久久亚洲毛片 | 国产偷抇久久精品a片69 | 丰满少妇高潮惨叫视频 | 300部国产真实乱 | 亚洲国产精品美女久久久久 | 欧洲vodafone精品性 | 少妇人妻大乳在线视频 | 无码精品人妻一区二区三区av | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 在线欧美精品一区二区三区 | 黑森林福利视频导航 | 丝袜 中出 制服 人妻 美腿 | 永久免费观看国产裸体美女 | 亚洲日韩av一区二区三区中文 | 精品久久综合1区2区3区激情 | 国産精品久久久久久久 | 欧美日韩视频无码一区二区三 | 中文无码精品a∨在线观看不卡 | 中文字幕av伊人av无码av | 人妻体内射精一区二区三四 | 蜜桃无码一区二区三区 | aⅴ亚洲 日韩 色 图网站 播放 | 无码av最新清无码专区吞精 | 国产乱人伦av在线无码 | 蜜桃臀无码内射一区二区三区 | 亚洲中文字幕在线观看 | 亚洲日韩中文字幕在线播放 | а√天堂www在线天堂小说 | 免费乱码人妻系列无码专区 | 97久久精品无码一区二区 | 色婷婷久久一区二区三区麻豆 | 特黄特色大片免费播放器图片 | 精品久久久中文字幕人妻 | 久久国产自偷自偷免费一区调 | 日韩在线不卡免费视频一区 | 我要看www免费看插插视频 | 亚洲熟妇色xxxxx欧美老妇 | www国产精品内射老师 | 欧美一区二区三区视频在线观看 | 在线天堂新版最新版在线8 | 国产卡一卡二卡三 | 国产激情一区二区三区 | 欧洲精品码一区二区三区免费看 | 亚洲爆乳大丰满无码专区 | 亚洲精品一区二区三区婷婷月 | 丰腴饱满的极品熟妇 | 人妻aⅴ无码一区二区三区 | 亚洲成av人影院在线观看 | 成人免费视频视频在线观看 免费 | 欧美刺激性大交 | 亚洲国产欧美日韩精品一区二区三区 | 国产精品无码永久免费888 | 真人与拘做受免费视频 | 欧美变态另类xxxx | 夜精品a片一区二区三区无码白浆 | 久久国产精品萌白酱免费 | 无码av免费一区二区三区试看 | 国产成人人人97超碰超爽8 | 欧美人与禽zoz0性伦交 | 熟女俱乐部五十路六十路av | 99riav国产精品视频 | 55夜色66夜色国产精品视频 | 特级做a爰片毛片免费69 | 国内丰满熟女出轨videos | 人妻无码久久精品人妻 | 亚洲欧美日韩成人高清在线一区 | 亚洲一区二区三区播放 | 人人超人人超碰超国产 | 亚洲色成人中文字幕网站 | 国产亚洲精品久久久久久 | 高清国产亚洲精品自在久久 | 国产在线无码精品电影网 | 牛和人交xxxx欧美 | 国产精品99久久精品爆乳 | 国产一区二区不卡老阿姨 | 久久综合给久久狠狠97色 | 欧美人与物videos另类 | 久久99热只有频精品8 | 中文字幕无线码免费人妻 | 久久久久国色av免费观看性色 | 日本www一道久久久免费榴莲 | 亚洲自偷自偷在线制服 | 宝宝好涨水快流出来免费视频 | 久久久婷婷五月亚洲97号色 | 精品无码一区二区三区爱欲 | 伊人久久大香线蕉午夜 | 亚洲色在线无码国产精品不卡 | 无码av最新清无码专区吞精 | 人妻少妇精品久久 | 久久久精品456亚洲影院 | 国产亚洲人成在线播放 | 377p欧洲日本亚洲大胆 | 中国女人内谢69xxxx | 黑人巨大精品欧美一区二区 | 欧美性生交xxxxx久久久 | 性生交大片免费看女人按摩摩 | 99久久99久久免费精品蜜桃 | 蜜臀aⅴ国产精品久久久国产老师 | 大肉大捧一进一出好爽视频 | 欧美精品国产综合久久 | 男女下面进入的视频免费午夜 | 欧美人与动性行为视频 | 亚洲の无码国产の无码影院 | 国产午夜精品一区二区三区嫩草 | 久久久久久av无码免费看大片 | 欧美激情综合亚洲一二区 | 亚洲欧美国产精品专区久久 | 国产后入清纯学生妹 | 免费观看黄网站 | 午夜福利试看120秒体验区 | 无码国产乱人伦偷精品视频 | aa片在线观看视频在线播放 | 国产特级毛片aaaaaa高潮流水 | 扒开双腿疯狂进出爽爽爽视频 | 岛国片人妻三上悠亚 | 国产后入清纯学生妹 | 国产精品久久福利网站 | 国产区女主播在线观看 | 偷窥日本少妇撒尿chinese | 色综合久久久久综合一本到桃花网 | 扒开双腿吃奶呻吟做受视频 | 亚洲国产av精品一区二区蜜芽 | 男人和女人高潮免费网站 | 人妻中文无码久热丝袜 | 捆绑白丝粉色jk震动捧喷白浆 | 日韩 欧美 动漫 国产 制服 | 一个人免费观看的www视频 | 人人妻人人澡人人爽人人精品浪潮 | 日韩亚洲欧美中文高清在线 | 领导边摸边吃奶边做爽在线观看 | 麻花豆传媒剧国产免费mv在线 | 亚洲无人区午夜福利码高清完整版 | 国产人成高清在线视频99最全资源 | 亚洲 欧美 激情 小说 另类 | 女人被男人躁得好爽免费视频 | 在线欧美精品一区二区三区 | 伊在人天堂亚洲香蕉精品区 | 女人被男人躁得好爽免费视频 | 国产特级毛片aaaaaa高潮流水 | 狠狠色噜噜狠狠狠狠7777米奇 | 色综合久久88色综合天天 | 精品久久久无码人妻字幂 | 午夜丰满少妇性开放视频 | 日本精品人妻无码77777 天堂一区人妻无码 | 天堂亚洲2017在线观看 | 中文字幕乱码人妻无码久久 | 国产偷自视频区视频 | 99久久久无码国产aaa精品 | 欧美xxxx黑人又粗又长 | 性欧美大战久久久久久久 | 野外少妇愉情中文字幕 | 成人无码视频在线观看网站 | 日本一区二区更新不卡 | 亚洲一区二区三区在线观看网站 | 日本欧美一区二区三区乱码 | 久久午夜无码鲁丝片午夜精品 | 久久精品国产日本波多野结衣 | 久久综合色之久久综合 | 欧美人与动性行为视频 | 亚洲人交乣女bbw | 国产精品嫩草久久久久 | 亚洲一区二区三区国产精华液 | 无码人妻丰满熟妇区五十路百度 | 性色欲情网站iwww九文堂 | 色欲av亚洲一区无码少妇 | 麻豆果冻传媒2021精品传媒一区下载 | 精品日本一区二区三区在线观看 | 亚洲精品一区二区三区在线 | 成人免费视频一区二区 | 日韩精品成人一区二区三区 | 无码精品人妻一区二区三区av | 夜夜躁日日躁狠狠久久av | 中文字幕无码免费久久9一区9 | 亚洲国产成人a精品不卡在线 | 欧美精品无码一区二区三区 | 中国大陆精品视频xxxx | 午夜无码区在线观看 | 中国女人内谢69xxxx | 无码人中文字幕 | 野狼第一精品社区 | 亚洲国精产品一二二线 | 婷婷色婷婷开心五月四房播播 | 麻豆人妻少妇精品无码专区 | 又大又紧又粉嫩18p少妇 | 黑人巨大精品欧美黑寡妇 | 久久精品人妻少妇一区二区三区 | 大地资源网第二页免费观看 | 中文字幕无码日韩欧毛 | 婷婷五月综合缴情在线视频 | 欧美性猛交xxxx富婆 | 自拍偷自拍亚洲精品10p | 偷窥村妇洗澡毛毛多 | 亚洲午夜久久久影院 | 免费乱码人妻系列无码专区 | 思思久久99热只有频精品66 | 高潮喷水的毛片 | 97人妻精品一区二区三区 | 97精品国产97久久久久久免费 | 亚洲热妇无码av在线播放 | 亚洲国产精华液网站w | 77777熟女视频在线观看 а天堂中文在线官网 | 久久精品国产一区二区三区肥胖 | 亚洲综合无码一区二区三区 | 国产av剧情md精品麻豆 | 免费国产成人高清在线观看网站 | 无人区乱码一区二区三区 | 国产成人无码a区在线观看视频app | √天堂中文官网8在线 | 国产精品久久久久久久9999 | 国产精品久久久一区二区三区 | 精品国产成人一区二区三区 | 国产成人综合色在线观看网站 | 久久久久人妻一区精品色欧美 | 成年美女黄网站色大免费全看 | 熟妇人妻无码xxx视频 | 国产av剧情md精品麻豆 | 97夜夜澡人人双人人人喊 | 国产亚洲精品久久久久久久 | 三上悠亚人妻中文字幕在线 | 久久久久亚洲精品中文字幕 | 国产亚洲精品久久久久久久久动漫 | 又黄又爽又色的视频 | 无码帝国www无码专区色综合 | 国产 浪潮av性色四虎 | 国产精品香蕉在线观看 | 伊人久久大香线蕉av一区二区 | 亚洲一区二区三区四区 | 伊人久久大香线蕉av一区二区 | 国产精品亚洲а∨无码播放麻豆 | 人妻少妇被猛烈进入中文字幕 | 丰满少妇弄高潮了www | 国产精品沙发午睡系列 | 国产成人精品三级麻豆 | 一区二区三区高清视频一 | 欧美精品无码一区二区三区 | 久久国产精品偷任你爽任你 | 国产高清不卡无码视频 | 国产av无码专区亚洲a∨毛片 | 免费无码的av片在线观看 | 亚洲成a人一区二区三区 | 性啪啪chinese东北女人 | 亚洲欧洲日本综合aⅴ在线 | 亚洲一区二区三区偷拍女厕 | 88国产精品欧美一区二区三区 | 性欧美大战久久久久久久 | 欧美人与动性行为视频 | 亚洲综合无码久久精品综合 | 久在线观看福利视频 | 欧美老妇交乱视频在线观看 | 国产亚洲精品久久久久久 | 国产乱人偷精品人妻a片 | 亚洲日韩精品欧美一区二区 | 300部国产真实乱 | 熟妇人妻无码xxx视频 | 国产亚洲精品久久久ai换 | 亚洲第一无码av无码专区 | 亚洲精品国产品国语在线观看 | 人人妻人人澡人人爽人人精品浪潮 | 成人性做爰aaa片免费看 | 老熟女重囗味hdxx69 | 亚洲欧美日韩成人高清在线一区 | a在线观看免费网站大全 | 国产偷国产偷精品高清尤物 | 麻豆国产人妻欲求不满 | 中文字幕人妻无码一夲道 | 亚洲人成网站色7799 | 狠狠cao日日穞夜夜穞av | 国产又爽又黄又刺激的视频 | 三上悠亚人妻中文字幕在线 | 久久午夜无码鲁丝片 | 麻豆av传媒蜜桃天美传媒 | 日韩人妻系列无码专区 | 欧美猛少妇色xxxxx | 久在线观看福利视频 | 人人妻人人澡人人爽欧美一区 | 国产精品多人p群无码 | 国产精品无码永久免费888 | 午夜福利试看120秒体验区 | 免费观看激色视频网站 | 精品国产麻豆免费人成网站 | 亚欧洲精品在线视频免费观看 | 狠狠色色综合网站 | 亚洲 高清 成人 动漫 | 丰满少妇女裸体bbw | 中文字幕精品av一区二区五区 | 亚洲综合在线一区二区三区 | 亚洲乱亚洲乱妇50p | 在线观看欧美一区二区三区 | 小sao货水好多真紧h无码视频 | 久久综合九色综合欧美狠狠 | 亚洲小说春色综合另类 | 性色欲网站人妻丰满中文久久不卡 | 国产又爽又黄又刺激的视频 | 午夜理论片yy44880影院 | 夜精品a片一区二区三区无码白浆 | 国产亚洲tv在线观看 | 人妻熟女一区 | 精品久久综合1区2区3区激情 | 最新版天堂资源中文官网 | 午夜肉伦伦影院 | 欧美人与牲动交xxxx | 日本va欧美va欧美va精品 | 中文毛片无遮挡高清免费 | 秋霞成人午夜鲁丝一区二区三区 | 欧美 日韩 人妻 高清 中文 | 天堂亚洲2017在线观看 | 免费无码的av片在线观看 | 亚洲成a人片在线观看无码 | 亚洲综合无码一区二区三区 | 精品国产一区二区三区av 性色 | 亚洲人成网站免费播放 | 四虎永久在线精品免费网址 | 欧美变态另类xxxx | 成在人线av无码免费 | 香蕉久久久久久av成人 | 中文字幕无码视频专区 | 久久人人爽人人人人片 | 亚洲爆乳精品无码一区二区三区 | 中文字幕无线码免费人妻 | 99riav国产精品视频 | 色五月五月丁香亚洲综合网 | 男女爱爱好爽视频免费看 | 国产性生交xxxxx无码 | 国内精品人妻无码久久久影院 | 两性色午夜视频免费播放 | 久久五月精品中文字幕 | 国产97在线 | 亚洲 | 中国女人内谢69xxxxxa片 | 国产麻豆精品精东影业av网站 | 久久午夜夜伦鲁鲁片无码免费 | 国产一区二区三区日韩精品 | 色婷婷久久一区二区三区麻豆 | 亚洲一区二区三区无码久久 | www国产亚洲精品久久网站 | a国产一区二区免费入口 | 正在播放东北夫妻内射 | 国产高清不卡无码视频 | 3d动漫精品啪啪一区二区中 | 色综合久久88色综合天天 | 伊在人天堂亚洲香蕉精品区 | 亚洲男人av天堂午夜在 | 国产精品久久久久久久9999 | 九九综合va免费看 | 久久久av男人的天堂 | 久久亚洲国产成人精品性色 | 无码一区二区三区在线 | 在线 国产 欧美 亚洲 天堂 | www一区二区www免费 | 成在人线av无码免费 | 国产成人精品视频ⅴa片软件竹菊 | 99久久人妻精品免费一区 | 亚洲无人区一区二区三区 | 红桃av一区二区三区在线无码av | 激情爆乳一区二区三区 | 欧美性黑人极品hd | 成人一区二区免费视频 | www一区二区www免费 | 97夜夜澡人人双人人人喊 | 亚洲国产高清在线观看视频 | 亚洲精品成a人在线观看 | 无码播放一区二区三区 | 久久人人爽人人人人片 | 欧洲精品码一区二区三区免费看 | 国产一区二区三区精品视频 | 国产无套内射久久久国产 | 国产精品久久久久久久影院 | 亚洲gv猛男gv无码男同 | 精品夜夜澡人妻无码av蜜桃 | 无码成人精品区在线观看 | 日日摸天天摸爽爽狠狠97 | 国产熟妇高潮叫床视频播放 | 4hu四虎永久在线观看 | 特级做a爰片毛片免费69 | 日本精品高清一区二区 | 亚洲国产成人a精品不卡在线 | 亚洲精品国产a久久久久久 | 国産精品久久久久久久 | 熟女俱乐部五十路六十路av | 在线亚洲高清揄拍自拍一品区 | 日日天日日夜日日摸 | 国产成人无码专区 | 无码福利日韩神码福利片 | 女人被男人躁得好爽免费视频 | 国产欧美熟妇另类久久久 | 久久精品人妻少妇一区二区三区 | 亚洲国产午夜精品理论片 | 一本久道久久综合狠狠爱 | 亚洲人成网站色7799 | 久久亚洲精品成人无码 | 亚洲中文字幕av在天堂 | 国产精品毛片一区二区 | 亚洲第一无码av无码专区 | 久在线观看福利视频 | av人摸人人人澡人人超碰下载 | √8天堂资源地址中文在线 | 色一情一乱一伦 | 亚洲 a v无 码免 费 成 人 a v | 无码国内精品人妻少妇 | 亚洲精品国偷拍自产在线观看蜜桃 | aⅴ在线视频男人的天堂 | 人妻有码中文字幕在线 | 婷婷五月综合激情中文字幕 | 色妞www精品免费视频 | 熟妇人妻中文av无码 | 极品嫩模高潮叫床 | 日本www一道久久久免费榴莲 | 中文字幕无码日韩专区 | 国产色在线 | 国产 | 人人妻人人澡人人爽欧美一区 | 国产精品人人妻人人爽 | 国产人妻久久精品二区三区老狼 | 强辱丰满人妻hd中文字幕 | 国产精品无码成人午夜电影 | 国产精品无码mv在线观看 | 天堂久久天堂av色综合 | 中文字幕无码乱人伦 | 亚洲日韩精品欧美一区二区 | 黑森林福利视频导航 | 最近中文2019字幕第二页 | 国产亲子乱弄免费视频 | 成人亚洲精品久久久久软件 | 无套内谢老熟女 | 亚洲午夜无码久久 | 丰满妇女强制高潮18xxxx | 丰满少妇人妻久久久久久 | 亚洲爆乳无码专区 | 国产精品久久久久无码av色戒 | yw尤物av无码国产在线观看 | 日韩人妻无码一区二区三区久久99 | 国产午夜视频在线观看 | 国产精品爱久久久久久久 | 久久99精品久久久久婷婷 | 图片区 小说区 区 亚洲五月 | 97se亚洲精品一区 | 99精品无人区乱码1区2区3区 | 国产熟妇另类久久久久 | 草草网站影院白丝内射 | 2019午夜福利不卡片在线 | 成人亚洲精品久久久久软件 | 熟女少妇在线视频播放 | 18禁黄网站男男禁片免费观看 | 久久精品国产一区二区三区 | 性色欲网站人妻丰满中文久久不卡 | 国产亚洲精品久久久久久大师 | 在线精品国产一区二区三区 | 在线亚洲高清揄拍自拍一品区 | 久久国产精品精品国产色婷婷 | 人妻无码久久精品人妻 | 夜夜高潮次次欢爽av女 | av香港经典三级级 在线 | 国产亚av手机在线观看 | 国产精品无码一区二区桃花视频 | 一本一道久久综合久久 | 波多野结衣 黑人 | 漂亮人妻洗澡被公强 日日躁 | 欧美日本免费一区二区三区 | 鲁一鲁av2019在线 | 欧美变态另类xxxx | 成年美女黄网站色大免费视频 | 亚洲欧美综合区丁香五月小说 | 草草网站影院白丝内射 | 激情国产av做激情国产爱 | 熟女俱乐部五十路六十路av | 奇米影视888欧美在线观看 | aⅴ在线视频男人的天堂 | 黑人巨大精品欧美黑寡妇 | 久久精品国产一区二区三区肥胖 | 伊人色综合久久天天小片 | 理论片87福利理论电影 | 人人爽人人爽人人片av亚洲 | 性欧美牲交在线视频 | 亚洲精品国产精品乱码不卡 | 日本va欧美va欧美va精品 | 丰满妇女强制高潮18xxxx | 日韩精品a片一区二区三区妖精 | 最新版天堂资源中文官网 | 精品无码一区二区三区的天堂 | 永久免费精品精品永久-夜色 | 无码av免费一区二区三区试看 | 鲁大师影院在线观看 | 午夜肉伦伦影院 | 国产无av码在线观看 | 国精品人妻无码一区二区三区蜜柚 | 欧美xxxx黑人又粗又长 | 全黄性性激高免费视频 | 无码一区二区三区在线观看 | 欧美午夜特黄aaaaaa片 | 在线欧美精品一区二区三区 | 乱人伦人妻中文字幕无码 | 国产精品成人av在线观看 | 国产乱人偷精品人妻a片 | 中文字幕无码av波多野吉衣 | 欧美国产日韩久久mv | 激情五月综合色婷婷一区二区 | 国产明星裸体无码xxxx视频 | 中文字幕无码日韩欧毛 | 国产精品高潮呻吟av久久 | 高清无码午夜福利视频 | 国精品人妻无码一区二区三区蜜柚 | 一区二区三区乱码在线 | 欧洲 | 人妻少妇被猛烈进入中文字幕 | 国产高清av在线播放 | 国产9 9在线 | 中文 | 亚洲gv猛男gv无码男同 | 亚洲自偷精品视频自拍 | 水蜜桃色314在线观看 | 精品aⅴ一区二区三区 | 精品国产av色一区二区深夜久久 | 国产偷国产偷精品高清尤物 | 天天综合网天天综合色 | 欧美国产日韩亚洲中文 | 成人女人看片免费视频放人 | 性欧美牲交xxxxx视频 | 国产精品无码mv在线观看 | 日本一区二区三区免费高清 | 激情人妻另类人妻伦 | 国产97色在线 | 免 | 精品乱码久久久久久久 | 中文字幕av无码一区二区三区电影 | 又大又黄又粗又爽的免费视频 | 日产国产精品亚洲系列 | 少妇厨房愉情理9仑片视频 | 欧美 日韩 人妻 高清 中文 | 性开放的女人aaa片 | 亚洲毛片av日韩av无码 | 久久精品人人做人人综合试看 | 高潮毛片无遮挡高清免费视频 | 亚洲国产成人a精品不卡在线 | 人人澡人人妻人人爽人人蜜桃 | 丰满人妻精品国产99aⅴ | 天天爽夜夜爽夜夜爽 | 久久精品一区二区三区四区 | 欧美人与动性行为视频 | 日本www一道久久久免费榴莲 | 国产真人无遮挡作爱免费视频 | 熟妇人妻激情偷爽文 | 少妇厨房愉情理9仑片视频 | 色窝窝无码一区二区三区色欲 | 久久久国产精品无码免费专区 | 亚洲日本va中文字幕 | 久久精品一区二区三区四区 | 亚洲国产精品无码久久久久高潮 | 在线天堂新版最新版在线8 | 亚洲va中文字幕无码久久不卡 | 97资源共享在线视频 | 久久精品国产精品国产精品污 | 亚洲乱码中文字幕在线 | 草草网站影院白丝内射 | 日韩精品无码一区二区中文字幕 | 在线观看国产一区二区三区 | 欧美日韩在线亚洲综合国产人 | 蜜桃视频韩日免费播放 | 7777奇米四色成人眼影 | 久久亚洲日韩精品一区二区三区 | 乱中年女人伦av三区 | 亚洲va欧美va天堂v国产综合 | 最近中文2019字幕第二页 | 又粗又大又硬又长又爽 | 国产绳艺sm调教室论坛 | 欧美老人巨大xxxx做受 | 娇妻被黑人粗大高潮白浆 | 成人毛片一区二区 | 熟妇人妻中文av无码 | 天天躁夜夜躁狠狠是什么心态 | 人妻与老人中文字幕 | 国产乱码精品一品二品 | 欧美日本免费一区二区三区 | 亚洲国产精品无码久久久久高潮 | 中文字幕无线码免费人妻 | 国产激情无码一区二区 | 免费观看又污又黄的网站 | 精品欧美一区二区三区久久久 | 亚洲欧美国产精品专区久久 | 色五月五月丁香亚洲综合网 | 一本久久a久久精品vr综合 | 99久久亚洲精品无码毛片 | 亚洲人交乣女bbw | 人妻中文无码久热丝袜 | 日本又色又爽又黄的a片18禁 | 亚洲国产成人a精品不卡在线 | 亚洲精品综合五月久久小说 | 亚洲日本一区二区三区在线 | 中文字幕乱码人妻二区三区 | 久久精品无码一区二区三区 | 天堂无码人妻精品一区二区三区 | 国产精品美女久久久 | 在线天堂新版最新版在线8 | aa片在线观看视频在线播放 | 午夜时刻免费入口 | 亚洲精品久久久久久久久久久 | 亚洲一区二区三区无码久久 | 超碰97人人做人人爱少妇 | 色欲久久久天天天综合网精品 | 精品无码一区二区三区的天堂 | a国产一区二区免费入口 | 蜜桃无码一区二区三区 | 九九在线中文字幕无码 | 久久久国产一区二区三区 | ass日本丰满熟妇pics | 国产超碰人人爽人人做人人添 | 精品亚洲韩国一区二区三区 | 国产成人综合色在线观看网站 | 欧美日韩亚洲国产精品 | 免费人成网站视频在线观看 | www一区二区www免费 | 98国产精品综合一区二区三区 | 亚洲爆乳精品无码一区二区三区 | 一本久道高清无码视频 | 性啪啪chinese东北女人 | 中文字幕乱码中文乱码51精品 | 精品 日韩 国产 欧美 视频 | 午夜理论片yy44880影院 | 四虎国产精品一区二区 | 狠狠色色综合网站 | 熟女少妇人妻中文字幕 | 伊人久久婷婷五月综合97色 | 久久久www成人免费毛片 | а天堂中文在线官网 | 亚洲精品国产精品乱码不卡 | 无码精品人妻一区二区三区av | 免费观看又污又黄的网站 | 亚洲日本在线电影 | 天天躁夜夜躁狠狠是什么心态 | 国产精品久久久久久亚洲影视内衣 | 十八禁真人啪啪免费网站 | 色诱久久久久综合网ywww | 伊人久久大香线蕉午夜 | 久久久久久久久蜜桃 | 97无码免费人妻超级碰碰夜夜 | 成人av无码一区二区三区 | 无码人妻黑人中文字幕 | 中文字幕无码乱人伦 | 国产免费无码一区二区视频 | 精品国产麻豆免费人成网站 | 亚洲爆乳精品无码一区二区三区 | 蜜桃无码一区二区三区 | 免费观看激色视频网站 | 国产亚洲视频中文字幕97精品 | 帮老师解开蕾丝奶罩吸乳网站 | 欧美人与善在线com | 精品国产青草久久久久福利 | 亚洲 另类 在线 欧美 制服 | 伊人色综合久久天天小片 | 亚洲中文字幕在线无码一区二区 | 国产av剧情md精品麻豆 | 亚洲精品国产第一综合99久久 | 在线精品亚洲一区二区 | 日本精品人妻无码77777 天堂一区人妻无码 | 欧美性生交xxxxx久久久 | 精品久久久中文字幕人妻 | 亚洲 高清 成人 动漫 | 人人妻人人藻人人爽欧美一区 | 精品厕所偷拍各类美女tp嘘嘘 | 欧美国产亚洲日韩在线二区 | 欧美xxxx黑人又粗又长 | 亚洲国产精品无码一区二区三区 | 亚洲爆乳大丰满无码专区 | 欧美 日韩 亚洲 在线 | 亚洲综合久久一区二区 | 日本精品久久久久中文字幕 | 中文字幕乱妇无码av在线 | 久久国产36精品色熟妇 | 亚洲色偷偷男人的天堂 | 精品久久久中文字幕人妻 | 中文字幕无码视频专区 | 国产亚洲人成a在线v网站 | 国产一精品一av一免费 | 草草网站影院白丝内射 | 丰满妇女强制高潮18xxxx | 婷婷五月综合缴情在线视频 | 捆绑白丝粉色jk震动捧喷白浆 | 天天做天天爱天天爽综合网 | 水蜜桃亚洲一二三四在线 | 在线观看免费人成视频 | 亚洲一区二区三区香蕉 | 99久久无码一区人妻 | 99久久亚洲精品无码毛片 | 成人动漫在线观看 | 国产一区二区三区影院 | 一二三四社区在线中文视频 | 老司机亚洲精品影院无码 | 永久免费观看美女裸体的网站 | 久青草影院在线观看国产 | √8天堂资源地址中文在线 | 精品一二三区久久aaa片 | 国产av一区二区精品久久凹凸 | 国产成人无码av一区二区 | 无码av免费一区二区三区试看 | 领导边摸边吃奶边做爽在线观看 | 日韩在线不卡免费视频一区 | 国产成人一区二区三区在线观看 | 久久亚洲日韩精品一区二区三区 | 日本丰满护士爆乳xxxx | 亚欧洲精品在线视频免费观看 | 熟妇人妻无码xxx视频 | 亚洲男女内射在线播放 | 无人区乱码一区二区三区 | 欧美黑人乱大交 | 精品午夜福利在线观看 | 无码纯肉视频在线观看 | 俺去俺来也在线www色官网 | 国产午夜亚洲精品不卡下载 | 伊人久久大香线蕉av一区二区 | 日本一卡二卡不卡视频查询 | 国产尤物精品视频 | 日日摸天天摸爽爽狠狠97 | 无遮无挡爽爽免费视频 | 国产亚洲美女精品久久久2020 | 亚洲日韩av片在线观看 | 精品人妻中文字幕有码在线 | 一本加勒比波多野结衣 | 亚洲精品综合一区二区三区在线 | 老太婆性杂交欧美肥老太 | 国产又爽又猛又粗的视频a片 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 超碰97人人射妻 | 国产极品视觉盛宴 | 国产做国产爱免费视频 | 无码人妻av免费一区二区三区 | √天堂资源地址中文在线 | 亚洲成av人综合在线观看 | 亚洲色欲久久久综合网东京热 | 亚洲乱码日产精品bd | www国产亚洲精品久久久日本 | 亚洲欧洲日本综合aⅴ在线 | 精品久久久久久亚洲精品 | 老司机亚洲精品影院 | 伊人久久婷婷五月综合97色 | 久久综合九色综合欧美狠狠 | 欧洲极品少妇 | 久久久久免费精品国产 | 波多野结衣av一区二区全免费观看 | 熟女俱乐部五十路六十路av | 午夜精品一区二区三区的区别 | 国产精品无码成人午夜电影 | 青草视频在线播放 | 亚洲精品一区二区三区在线观看 | 在教室伦流澡到高潮hnp视频 | 日韩精品乱码av一区二区 | 少妇人妻大乳在线视频 | 亚洲综合在线一区二区三区 | 午夜精品久久久久久久 | 国产亚洲精品久久久闺蜜 | 人人妻人人澡人人爽人人精品 | 中文字幕+乱码+中文字幕一区 | 99国产精品白浆在线观看免费 | 成人av无码一区二区三区 | 99在线 | 亚洲 | 人妻少妇精品视频专区 | 欧美 亚洲 国产 另类 | 精品偷拍一区二区三区在线看 | 巨爆乳无码视频在线观看 | 亚洲综合无码一区二区三区 | 亚洲 日韩 欧美 成人 在线观看 | 国产精品久久久久无码av色戒 | 免费无码一区二区三区蜜桃大 | 亚洲中文字幕成人无码 | 国产suv精品一区二区五 | 精品日本一区二区三区在线观看 | 无码av最新清无码专区吞精 | 欧美成人午夜精品久久久 | 蜜臀aⅴ国产精品久久久国产老师 | 欧美亚洲国产一区二区三区 | 日本www一道久久久免费榴莲 | 中文字幕av无码一区二区三区电影 | 中文字幕无码热在线视频 | 色婷婷久久一区二区三区麻豆 | 精品熟女少妇av免费观看 | 国产色xx群视频射精 | 男女爱爱好爽视频免费看 | 人人澡人摸人人添 | 久久久无码中文字幕久... | 亚洲熟女一区二区三区 | 亚洲欧美色中文字幕在线 | 亚洲欧洲中文日韩av乱码 | 一区二区传媒有限公司 | 国产精品沙发午睡系列 | 少妇高潮喷潮久久久影院 | 亚洲中文字幕va福利 | 国产精品久久久久9999小说 | 18禁止看的免费污网站 | 性史性农村dvd毛片 | 国产一区二区三区日韩精品 | 我要看www免费看插插视频 | 国产精品内射视频免费 | 午夜精品一区二区三区在线观看 | 精品国产一区av天美传媒 | 亚洲日韩一区二区 | 在线观看免费人成视频 | 中文无码成人免费视频在线观看 | 久久99国产综合精品 | 亚洲国产精品无码一区二区三区 | 中文字幕乱码人妻无码久久 | www国产亚洲精品久久网站 | 少妇被黑人到高潮喷出白浆 | 日本免费一区二区三区最新 | 国产午夜手机精彩视频 | 亚洲成a人片在线观看无码3d | 日韩精品无码一区二区中文字幕 | 一本无码人妻在中文字幕免费 | 99久久亚洲精品无码毛片 | 欧美日韩色另类综合 | 久久国产精品偷任你爽任你 | 丰满人妻被黑人猛烈进入 |