• <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>
            隨筆 - 60, 文章 - 0, 評論 - 197, 引用 - 0
            數據加載中……

            C++ 學習筆記

            一   編程設計
                 1.將程序劃分為多個子系統,包括子系統間的接口和依賴關系、子系統間的數據流、在各子系統間的來回輸入輸出、以及總的線程模型。

                 2.各個子系統的具體細節,包括進一步細分的類、類層次體系、數據結構、算法、特定的線程模型和錯誤處理。

            二   設計流程
                 1.需求:功能需求和性能需求。
                 2.設計步驟
                   (1)把程序劃分為通用功能子系統,并明確子系統的接口和交互。
                   (2)把這些子系統列在一個表中,并表示出子系統的高層行為或功能、子系統向其它子系統提供的接口,及此子系統使用了其他子系統的哪些接口。
                   (3)選擇線程模型:確定使用多少個線程,明確線程的交互并為共享數據指定加鎖機制。
                   (4)為每個子系統指定層次體系
                   (5)為每個子系統指定類、數據結構、算法和模式
                   (6)為每個子系統指定錯誤處理(系統錯誤 + 用戶錯誤),指定是否使用異常

            三   C++ 的設計原則
                 1.抽象:將接口與實現相分離
                 2.重用:代碼重用和思想重用

            四   對象關系
                 1.has-a 關系(聚集)
                 2.is-a  關系(繼承)
                 3.組織對象層次體系:
                  (1)將類按有意義的功能加以組織。
                  (2)將共同的功能放到超類中,從而支持代碼重用。
                  (3)避免子類過多的覆蓋父類的功能。

            五   重用設計
                 1.建立可重用的代碼結構
                  (1)避免將無關或邏輯上分離的概念混在一起
                  (2)把程序劃分為子系統
                  (3)使用類層次體系來分離邏輯概念
                  (4)使用聚集來分離邏輯概念
                  (5)對通用數據結構和算法使用模板
                  (6)提供適當的檢查和防護

            六   設計易于使用的接口
                 1.開發直觀的接口
                 2.不要遺漏必要的功能
                 3.提供簡潔的接口
                  (1)消除重復的接口
                  (2)只提供所需的功能
                  (3)適當的限制庫的使用
                 4.提供文檔和注釋
                  (1)公共的文檔應指定行為,而不是底層實現

            七   設計通用的接口
                 1.提供多種方法來完成同一功能
                 2.提供定制能力

            八   協調一般性和通用性
                 1.提供多個接口
                 2.優化常用功能

            九   代碼注釋
                 (1)前綴注釋
                    * 文件/類名
                    * 最后一次修改時間
                    * 原作者
                    * 文件所實現特性的編號 (特性 ID)
                    * 版權信息
                    * 文件/類的簡要描述
                    * 未完成的特性
                    * 已知的 bug

                 (2)注釋示例
                    /*
                     * Watermelon.cpp
                     *
                     * $Id: Watermelon.cpp,v 1.6 2004/03/10 12:52:33 klep Exp $
                     *
                     * Implements the basic functionality of a watermelon. All
                     * unit are expressed in terms of seeds per cubic centimeter
                     * Watermelon theory is based on the white paper "Alogorthms
                     * for Watermelon Processing."
                     *
                     * The following code is (c)copyright 2004. FruitSoft, Inc.
                     * All right reserved
                     */

            十   編寫代碼
                 1.類定義在 C++ 中是一條語句,因此必須以分號結束。
                 2.:: 指作用域解析操作符。
                 3.在棧和堆上使用對象的區別
                   (1)在棧上創建對象
                      SpreadsheetCell myCell, anotherCell;

                   (2)在堆上使用對象
                      SpreadsheetCell *myCellp = new SpreadsheetCell();

                   (3)如果用 new 來分配一個對象,用完該對象時要用 delete 來釋放

                 4.C++ 程序員通常把構造函數稱為 "ctor"

                 5.使用構造函數
                   (1)在棧上使用構造函數
                      SpreadsheetCell myCell(5);

                   (2)在堆上使用構造函數
                      SpreadsheetCell *myCell = new SpreadsheetCell(5);
                      delete myCell;

                   (3)不要嘗試從類的一個構造函數調用另一個構造函數

                 6.使用默認構造函數
                   (1)在棧上使用構造函數
                      SpreadsheetCell myCell;  //right
                      SpreadsheetCell myCell();//wrong

                   (2)在棧上創建對象時,要去掉默認構造函數的小括號
                   (3)在堆上使用默認構造函數
                      SpreadsheetCell *myCellp = new SpreadsheetCell();

                   (4)什么時候需要使用構造函數
                      SpreadsheetCell cells[3];//fails comilation without default ctor
                     SpreadsheetCell *myCellp = new SpreadsheetCell[10];//alse fails

                   (5)使用初始化列表
                      1)初始化列表允許在創建數據成員的同時完成數據成員的初始化
                      2)使用初始化列表的情況

                  數據成員                                         解釋
                  ------------------------------------------------------------------
                  const 數據成員                              必須在創建時提供值
                  引用數據成員                               引用無法獨立存在
                  沒默認構造函數的對象成員       對象成員無法初始化
                  沒有默認構造函數的超類           見后面 
                  ------------------------------------------------------------------

                 7.對象的撤銷
                   (1)析構函數僅用于釋放內存或釋放其他資源是一個不錯的想法

                 8.淺復制與深復制
                   (1)淺復制:只是從源對象直接將數據成員復制或賦值到目標對象
                   (2)深復制:非淺復制
                   (3)只要在類中動態分配了內存,就應該編寫自己的復制構造函數來提供內存的深復制
                   (4)在對一個對象進行賦值前,必須先釋放此對象的所有動態分配的內存
                   (5)只要類會動態分配內存,就需要編寫析構函數、復制構造函數、賦值操作符
                   (6)禁止對象賦值,可將復制構造函數與賦值操作符聲明為私有成員
                   (7)不必為私有復制構造函數和賦值操作符提供實現,編譯器不要求

            十一 精通類和對象
                 1.不能在靜態方法中訪問非靜態數據成員
                 2.保證一個對象不會修改數據成員,可用 const 來標記

                 3.保證一個方法不會修改數據成員,可用 const 來標記
                   (1)在類定義中的聲明 double getValue() const;
                   (2)在源文件中的實現
                      double Spreadsheet::getValue() const
                     {
                        return this.mValue;
                     }

                 4.非 const 對象可以調用 const 和非 const 方法,const 對象只能調用const 方法

                 5.應將所有不會修改對象的方法都聲明為 const,并在程序中使用 const對象引用

                 6.將變量置為 mutable,這樣編譯器允許在 const 方法中修改這個變量
                 7.C++ 不允許僅基于方法的返回類型而重載一個方法名
                 8.默認參數:從最右參數開始的連續參數表
                 9.只能在方法聲明中指定默認參數,在定義中并不指定
                 10一個構造函數的所有參數都有默認值,此函數會作為默認構造函數
                 11能利用默認參數做到的事情,利用方法重載也可以做,用你最熟悉的

                 12內聯:將方法體或函數體直接插入到代碼調用處(相當于 #define 宏的安
                   全版本),內聯示例如下:

                   (1)在類的源文件(SpreadsheetCell.cpp)
                   inline double SpreadsheetCell::getValue() const
                   {
                       mNumAccess++;
                       return mValue;
                   }

                   (2)或在類的聲明文件中直接實現此方法而不用 inline 關鍵字
                   //SpreadsheetCell.h
                   double getValue() const (mNumAccesses++; return mValue;}

                 13友元可以訪問指定類中的 protected 和 private 數據成員和方法
                   (1)聲明友元類
                      class SpreadsheetCell
                      {
                         public:
                             friend class Spreadsheet;
                            //code omitted here
                      };

                   (2)聲明友元方法
                      class SpreadsheetCell
                     {
                         public:
                             friend bool checkSpreadsheetCell();
                             //code omitted here
                     };


            十二 C++ 中的繼承機制
                 1.超類指針(引用)在引用子類時,了類仍然會保留它們覆蓋的方法。而在
                   強制類型轉換成超類對象時,子類會失去它們的獨有特性。覆蓋方法和子
                   類數據的丟失稱為切割。

                 2.作為一條經驗,要把所有的方法都用 virtual 聲明 (包括析構函數,但
                   是不包括構造函數) 來避免因遺漏關鍵字 virtual 而產生的相關問題。

                 3.virtual 用法示例:
                   class Sub : public Super
                   {
                       public:
                       Sub();
                       virtual void someMethod();
                       virtual void someOtherMethod();
                   }

                 4.要把所有的析構函數都用 virtual 聲明

                 5.強制類型轉換
                   (1)靜態轉換 static_cast<type>
                      示例:
                      Sub* mySub = static_cast<Sub*>(inSuper);

                   (2)動態轉換 dynamic_cast<type>
                      示例:
                      Sub* mySub = dynamic_cast<Sub*>(inSuper);
                      if (mySub == NULL)
                     {
                          //proceed to access sub methods on mySub
                     }
              
               注意:如果對指針不能進行動態類型轉換,指針則為 NULL, 而不是指
               向無意義的數據。

                 6.進行向上強制類型轉換時,要使用指向超類的指針或引用來避免切割問題。

                 7.純虛方法與抽象基類
                   (1)純虛方法: 在類定義中顯示未定義的方法。
                   (2)抽象類: 含有純虛方法的類(不能實例化)。
                   (3)純虛方法語法定義: 在類定義中簡單的設置方法等于 0,在 cpp 文件
                      中不要編寫其實現代碼。
               示例:
               class SpreadsheetCell
               {
                   public:
                       SpreadsheetCell();
                       virtual ~SpreadsheetCell();
                       virtual void set(const std::string instring) = 0;
                       virtual std::string getString() const = 0;
                 };

                 8.定制類型轉換函數
                   (1)double 類型轉換成 string 類型
                      #include <iostream>
                      #include <sstream>
              
                      double inValue;
                      string myString;

                      ostringstream ostr;
                      ostr << inValue;
                      myString = ostr.str();

                   (2)string 類型轉換成 double 類型
                      #include <iostream>
                      #include <sstream>
              
                      double myDouble;
                      string inString;
              
                      istringStream istr(inString);
                      istr >> myDouble;
                     if (istr.fail())
                    {
                       myDouble = 0;
                    }

                 9.使用預編譯指令避免重復包含頭文件
                   #ifndef _TEST_H_
                   #define _TEST_H_
                   // include header files here      
                   // other code omitted here

                   #endif
              
            十三 覆蓋方法的特殊情況
                 1.在 C++ 中不能覆蓋靜態方法。
                   (1)不能同時用 virtual 和 static 聲明一個方法。
                   (2)在對象上可以調用 static 方法,但 static 方法只存在于類中。

            十四 利用模板編寫通用代碼
                 1.模板相關概念
                   (1)類模板: 存儲對象的容器或數據結構。
                   (2)模板的語法:
                      template <typename T>
                     class Grid
                     {
                         public:
                             Grid(int inWidth, int inHeight);
                             Grid(const Grid<T>& src);
                             Grid<T>& operator=(const Grid<T>& rhs);
                             T& getElementAt(int x, int y);
                             const T& getElementAt(int x, int y);
                             void setElementAt(int x, int y, const T& inElem);

                         protected:
                             void copyFrom(const Grid<T>& src);
                             T** mCells;
                    };
                    (3)語法解釋
                        template <typename T> : 指在類型 T 上定義的模板。
                        Grid<T> : Grid 實際上是模板名。
                        Grid<T> : 將作為類模板中的類名。

             (4)模板定義(實現)
                template <typename T>
                Grid<T>::Grid(int inWidth, int inHeight)
                {
                    mCells = new T* [mWidth];
                    for (int i = 0; i < mWidth; i++)
                    {
                        mCells[i] = new T[mHeight];
                    }
                }

             (5)模板實例化
                Grid<int> myIntGrid;

            十五 C++ 中的一些疑難問題
                 1.引用
                   (1)定義: 另一個變量的別名, 對引用的修改會改變其所指向的變量。
                   (2)引用變量必須在創建時就初始化。
                      int  x = 3;   // right
                      int& xRef = x;// right
                      int& emptyRef;//wrong
                      注: 類的引用數據成員可在構造函數的初始化列表中初始化。

                   (3)不能創建指向未命名值的引用(const 常量值除外)
                      int& unnameRef = 5;      //does not compile
                      const int& unnameRef = 5;//works as expect

                   (4)修改引用: 引用總是指向初始化時指定的那個變量。
                      int x = 3, y = 4;
                      int& xRef = x;
                      xRef = y; // change x value to 4, doesn't make refer to y;
                      xRef = &y; // doesn't compile, type not match
                     注: 引用指向的變量在初始化之后不能再改變, 只能改變此變量的值

                   (5)指針引用和引用指針
                      //指針引用示例(指向指針的引用)
                      int*  intP;
                      int*& ptrRef = intP;
                      ptrRef = new int;
                     *ptrRef = 5;

                     注:不能聲明指向引用的引用, 也不能聲明引用指針(指向引用的指針)
                     int x = 3;
                     int& xRef = x;
                     int&& xDoubleRef = xRef; // not compile
                     int&* refPtr = &xRef; // not compile
              
                   (6)傳引用vs傳值
                      1)效率。復制大對象和結構要花費很長時間。
                      2)正確性。不是所有的對象都允許傳值或正確的支持深復制。
                      3)不想修改原對象,又利用以上兩優點,可在參數前加 const。
                     4)對簡單內置類型(如int或double)要傳值,其它所有情況可傳引用。

                   (7)引用vs指針
                      1)引用讓程序清晰,易于理解。
                      2)引用比指針安全,不存在無效的引用,不需要明確解除引用。
                      3)除非需要動態分配內存或在其它地方要改變或釋放指針指向的值,否則都應使用引用而非指針。
                
                 2.疑難字 const
                   (1)const 變量
                      使用 const 來聲明變量,對不能對其修改,以保護變量。

                   (2)const 指針
                   //不能改變指針指向的值
                      const int* ip;
                      ip = new int[10];
                      ip[4] = 5; // not compile
                    或
                      int const* ip;
                      ip = new int[10];
                      ip[4] = 5; // not compile
             
                      //不能改變指針自身
                      int* const ip;
                      ip = new int[10]; // not compile
                      ip[4] = 5;

                     //既不能改變指針也不能改變指針指向的值
                     const int* const ip = NULL;(無用的指針)
                      注: const 可以放在類型前也可以放在類型后
              
                   (3)const 應用規則
                      const 應用于其左則的第一項。

                   (4)把對象參數傳遞時,默認的做法是把傳遞 const 引用。

                   (5)const 方法
                      用 const 標識類方法,可以防止方法修改類中不可變的數據成員。

                 3.關鍵字 static
                   (1)關于連接: C++ 中的每個源文件是獨立編譯的,得到的對象連接在一
                      起。

                   (2)外部連接: 一個源文件中每個名字(如函數或全局變量)對其它源文件
                      是可用的。

                   (3)內部連接: 一個源文件中每個名字(如函數或全局變量)對其它源文件
                      是不可用的。內部連接也叫靜態連接。

                   (4)函數和全局變量默認是外部連接。

                   (5)聲明前加 static 可指定為內部連接。

                 4.關鍵字 extern
                   (1)作用: 與 static 相對,用來為位于它前面的名字聲明外部連接。
                   (2)extern 用法
                      // AnotherFile.cpp
                     extern int x; // 只是聲明 x 為外部連接而不分配內存
                     int x = 3;    //顯示定義以分配內存
                    或
                      extern int x = 3;//聲明和定義一起完成

                      //FirstFile.cpp
                     extern int x;
                     cout << x << endl;

                  5.強制類型轉換
                  (1)const_cast<type> 去除變量的常量性。
                  示例:
                  void g(char* str)
                  {
                      // body omitted here
                  }
                  void f(const char* str)
                  {
                      g(const_cast<char*>(str));
                      // other code omitted here
                  }      

             (2)static_cast<type> 顯示的完成 C++ 語言支持的轉換。
                示例:
                int x = 3;
                double result = static_cast<double>(i) /10;

                注: static_cast 進行類型轉換時并不完成運行時類型檢查。

             (3)dynamic_cast<type>
                1)對類型強制轉換完成運行時類型檢查。
                2)對指針轉換失敗時會返回 NULL。
                3)對引用轉換失敗時會拋出 bad_cast 異常。

             
            6.函數指針
                    (1)定義: 把函數地址作為參數,可以像變量一樣使用。
                    (2)定義函數指針: typedef bool(*YesNoFcn) (int, int);
                    (3)用法示例

                       //定義函數指針類型
                       typedef string(*YesNoFcn)(int, int);

                       void test(int value1, int values2, YesNoFcn isFunction)
                      {
                         cout << isFunction(value1, value2);
                      }

                     string intEqual(int intItem1, int intItem2)
                     {
                        return (intItem1 == intItem2) ? "match" : "not match";
                     }

                     //使用函數指針
                      test(1, 1, &intEqual);

                     注: & 是可選的


            十六 C++ 中的 I/O 操作
                 1.使用流
                   (1)每個輸入流都有一個相關聯的源,每個輸出流都有一個相關聯的目的。

                   (2)cout 和 cin 都是在 C++ 的 std 命名空間中預定義的流實例。

                   (3)流的三種類型:
                      1)控制臺輸入輸出流。
                      2)文件流。
                      3)字符串流。

                   (4)輸出流
                      1)輸出流在頭文件 <ostream> 中定義,輸入流在 <istream> 中定義<iosream> 中定義了輸入輸出流。

                      2)cout 和 cin 指控制臺輸入輸出流。

                      3)<< 操作符是使用輸出流的最簡單的方法。

                      4)流其它的輸出方法
                         1)put() 和 wirte()
                         2)flush() 刷新輸出
             
                      5)處理輸出錯誤
                         1)cout.good()  流是否處于正常的可用狀態。
                         2)cout.bad()   流輸出是否發生了錯誤。
                         3)cout.fail()  如果最近的操作失敗則返回 true
                         4)cout.clear() 重置流的錯誤狀態

               6)輸出控制符
                 1)endl         輸出回車并刷新其緩沖區
                 2)hex oct dec  以十六/八/十進制輸出
                 3)setw         設置輸出數值數據時的字段占位符
                 4)setfill    設置填充空位的占位符

                   (5)輸入流
                      1)>> 輸入流操作符
                      2)輸入方法
                          1)get()    僅僅返回流中的下一個字符
                          2)unget()    引起流回退一個位置
                          3)peek()    預覽下一個值
                          4)getline()    從輸入流中取一行數據

                      3)處理輸入錯誤
                         1)good()
                         2)eof()

                   (6)字符串流
                      1)<ssteam>    定義了字符串流的頭文件
                     2)ostringstream  字符串輸出流
                     3)istringstream  字符串輸入流

                   (7)文件流
                      1)<fstream>      定義了文件流的頭文件
                      2)ifstream    文件輸入流
                      3)ofstream    文件輸出流
                      4)seek()    定位流的位置
                      5)tell()    查詢流當前的位置

                   (8)鏈接流
                      1)定義: 在任何輸入流與輸出流之間建立連接,一旦訪問就刷新輸出。
                      2)實現: 用輸入流的 tie() 方法
                      3)示例
                        #include <iostream>
                       #inlcude <fstream>
                       #include <string>

                       main()
                       {           
                            ifstream inFile("input.txt");
                           ofstream outFile("output.txt");
                
                            //set up a link between inFile and outFile.
                            inFile.tie(&outFile);

                           string nextToken;
                           inFile >> nextToken;
                     }


            十七 C++ 中的異常
                 1.拋出和捕獲異常
                   (1)<exception> 定義異常類的頭文件。
                   (2)拋出異常對象 throw exception()
                   (3)向量的使用(整型)
                    vector<int> myInts;
                    for (int i = 0; i < 10; i++)
                    {
                         myInts.push_back(i);// 增加元素
                         cout << myInts[i];
                    }

                   (4)string 風格的字符串轉換成 C 風格的字符串
                      string myString = "string style string";
                      char* cStyleStrng = myString.c_str();

                   (5)捕獲運行時異常
                      try
                     {
                        ...
                      }
                      catch (const runtime_error& e)
                     {
                       ...
                     }

                   (6)拋出和捕獲無效參數異常
                      throw invalid_argument("");

                     try
                      {
                        ...
                      }
                      catch (const invalid_argument& e)
                      {
                         ...
                      }

                     注: runtime_error 和 invalid_argument 定義在頭文件<stdexcept> 中

                   (7)匹配任何異常(...)
                      try
                      {
                        // code omitted here
                      }
                      catch (...)
                      {
                        // code omitted
                      }
                     注: 不建議使用這種方式

                   (8)使用拋出列表
                      1)拋出列表: 一個函數或方法能拋出的異常列表
                      2)必須為函數聲明和實現都提供拋出列表
                      3)沒有拋出列表就可以拋出任何異常
                     4)空的拋出列表不允許拋出任何異常

                   (9)在覆蓋方法中修改參數列表
                      1)從列表中刪除異常
                      2)增加超類拋出列表中異常的子類
                      3)不能完全刪除拋出列表

                   (10)顯示異常消息
                       可調用 exception 或子類的 what() 方法顯示捕獲到的異常消息
                       示例:
                       try
                       {
                           ...
                       }
                       catch (const exception& e)
                       {
                           cerr << e.what() << endl;
                           exit(1);
                       }
                        
                   (11)多態地捕獲異常
                       1)在多態地捕獲異常時,要確保按引用捕獲異常。如果按值捕獲異常,就會遇到切割問題,丟失對象的信息。

                       2)按引用捕獲異常可以避免不必要的復制開銷

                   (12)如果異常處理不夠仔細,就會導致內存和資源泄漏
                       示例
                       func ()
                      {
                        string str1;
                        string* str2 = new string();
                        throw exception();
                        delete str2;     // 內存泄漏
                      }

                   (13)使用智能指針防止內存泄漏
                       #include <memory> // 定義智能指針的頭文件
                       using namespace std;
                       func ()
                       {
                           string str1;

                           // 智能指針,不用自己手動釋放
                          auto_ptr<string> str2(new string("hello"));
                          throw exception();
                       }

                   (14)處理內存分配錯誤
                       1)new 和 new [] 分配內存失敗默認拋出 bad_alloc 異常
                       2)可用 try/catch 捕獲異常處理內存分配失敗
                       3)示例:
                         try
                         {
                             ptr = new int[numInts];
                         }
                         catch (bad_alloc& e)
                        {
                          cerr << "Unable to alloc memory!" << endl;
                          return ;
                        }
                     或
                      1)用 new(nothrow) 在內存分配失敗時返回 NULL 來處理
                      2)示例:
                         ptr = new(nothrow) int[numInts];
                        if (ptr == NULL)
                        {
                           cerr << "Unable to alloc memory!" << endl;
                           return;
                        }
                     或
                       1)用 set_new_handler() 回調函數定制分配失敗時的行為
                       2)示例
                          void myNewHandler()
                         {
                            cerr << "Unable to allocate memory!" << endl;
                            abort(); // 終止程序 <cstdlib>
                         }
                        
                         #include <new>
                        #include <cstdlib>
                        #include <iostream>
                        using namespace std;
                 
                        int main(int argc, char** argv)
                       {
                           new_handler oldHandler = set_new_handler(myNewHandler);

                          // code omitted here

                         set_new_handler(oldHandler);
                         return (0);
                     }

            posted on 2007-08-20 16:15 Normandy 閱讀(950) 評論(1)  編輯 收藏 引用 所屬分類: Programming

            評論

            # re: C++ 學習筆記  回復  更多評論   

            做的 professional C++這本書上的筆記吧!很好.....
            2008-01-21 15:16 | LJL
            人人狠狠综合久久88成人| 久久国产精品免费一区| 国产成人精品综合久久久| 亚洲精品乱码久久久久久中文字幕 | 丁香五月综合久久激情| 国内精品久久久久久久coent| 久久久久国色AV免费看图片| 久久精品国产亚洲AV忘忧草18 | 性欧美丰满熟妇XXXX性久久久| 久久青青草原亚洲av无码app| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 日本精品久久久久久久久免费| 亚洲国产精品久久电影欧美| 久久青青草原国产精品免费| 一本久道久久综合狠狠躁AV| 天天爽天天爽天天片a久久网| 99久久香蕉国产线看观香| 香港aa三级久久三级| 亚洲色婷婷综合久久| 日产久久强奸免费的看| 久久国产高清字幕中文| 欧美亚洲国产精品久久高清| 久久久黄片| 777久久精品一区二区三区无码 | 99久久综合国产精品免费| 成人精品一区二区久久| 91视频国产91久久久| 久久精品日日躁夜夜躁欧美| 青青热久久国产久精品 | 香蕉久久夜色精品国产尤物| 国产精品gz久久久| 91久久精品国产成人久久| 久久久91精品国产一区二区三区| 无码人妻精品一区二区三区久久| 综合久久精品色| 午夜视频久久久久一区 | 99蜜桃臀久久久欧美精品网站| 久久精品无码一区二区app| 久久久久国色AV免费观看| 狠狠久久综合| 香港aa三级久久三级老师2021国产三级精品三级在 |