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

            Design&Art

            C++博客 首頁 新隨筆 聯(lián)系 聚合 管理
              26 Posts :: 0 Stories :: 38 Comments :: 0 Trackbacks

            #

            (zz) C++箴言:理解typename的兩個(gè)含義

              問題:在下面的 template declarations(模板聲明)中 class 和 typename 有什么不同?
            template<class T> class Widget; // uses "class"
            template<typename T> class Widget; // uses "typename"
              答案:沒什么不同。在聲明一個(gè) template type parameter(模板類型參數(shù))的時(shí)候,class 和 typename 意味著完全相同的東西。一些程序員更喜歡在所有的時(shí)間都用 class,因?yàn)樗菀纵斎搿F渌耍òㄎ冶救耍└矚g typename,因?yàn)樗凳局@個(gè)參數(shù)不必要是一個(gè) class type(類類型)。少數(shù)開發(fā)者在任何類型都被允許的時(shí)候使用 typename,而把 class 保留給僅接受 user-defined types(用戶定義類型)的場合。但是從 C++ 的觀點(diǎn)看,class 和 typename 在聲明一個(gè) template parameter(模板參數(shù))時(shí)意味著完全相同的東西。

              然而,C++ 并不總是把 class 和 typename 視為等同的東西。有時(shí)你必須使用 typename。為了理解這一點(diǎn),我們不得不討論你會在一個(gè) template(模板)中涉及到的兩種名字。

              假設(shè)我們有一個(gè)函數(shù)的模板,它能取得一個(gè) STL-compatible container(STL 兼容容器)中持有的能賦值給 ints 的對象。進(jìn)一步假設(shè)這個(gè)函數(shù)只是簡單地打印它的第二個(gè)元素的值。它是一個(gè)用糊涂的方法實(shí)現(xiàn)的糊涂的函數(shù),而且就像我下面寫的,它甚至不能編譯,但是請將這些事先放在一邊——有一種方法能發(fā)現(xiàn)我的愚蠢:
            template<typename C> // print 2nd element in
            void print2nd(const C& container) // container;

             
            // this is not valid C++!
             if (container.size() >= 2{
              C::const_iterator iter(container.begin()); 
            // get iterator to 1st element
              ++iter; // move iter to 2nd element
              int value = *iter; // copy that element to an int
              std::cout << value; // print the int
             }

            }
              我突出了這個(gè)函數(shù)中的兩個(gè) local variables(局部變量),iter 和 value。iter 的類型是 C::const_iterator,一個(gè)依賴于 template parameter(模板參數(shù))C 的類型。一個(gè) template(模板)中的依賴于一個(gè) template parameter(模板參數(shù))的名字被稱為 dependent names(依賴名字)。當(dāng)一個(gè) dependent names(依賴名字)嵌套在一個(gè) class(類)的內(nèi)部時(shí),我稱它為 nested dependent name(嵌套依賴名字)。C::const_iterator 是一個(gè) nested dependent name(嵌套依賴名字)。實(shí)際上,它是一個(gè) nested dependent type name(嵌套依賴類型名),也就是說,一個(gè)涉及到一個(gè) type(類型)的 nested dependent name(嵌套依賴名字)。

              print2nd 中的另一個(gè) local variable(局部變量)value 具有 int 類型。int 是一個(gè)不依賴于任何 template parameter(模板參數(shù))的名字。這樣的名字以 non-dependent names(非依賴名字)聞名。(我想不通為什么他們不稱它為 independent names(無依賴名字)。如果,像我一樣,你發(fā)現(xiàn)術(shù)語 "non-dependent" 是一個(gè)令人厭惡的東西,你就和我產(chǎn)生了共鳴,但是 "non-dependent" 就是這類名字的術(shù)語,所以,像我一樣,轉(zhuǎn)轉(zhuǎn)眼睛放棄你的自我主張。)

              nested dependent name(嵌套依賴名字)會導(dǎo)致解析困難。例如,假設(shè)我們更加愚蠢地以這種方法開始 print2nd:
            template<typename C>
            void print2nd(const C& container)
            {
             C::const_iterator 
            * x;
             
            //
            }
              這看上去好像是我們將 x 聲明為一個(gè)指向 C::const_iterator 的 local variable(局部變量)。但是它看上去如此僅僅是因?yàn)槲覀冎?C::const_iterator 是一個(gè) type(類型)。但是如果 C::const_iterator 不是一個(gè) type(類型)呢?如果 C 有一個(gè) static data member(靜態(tài)數(shù)據(jù)成員)碰巧就叫做 const_iterator 呢?再如果 x 碰巧是一個(gè) global variable(全局變量)的名字呢?在這種情況下,上面的代碼就不是聲明一個(gè) local variable(局部變量),而是成為 C::const_iterator 乘以 x!當(dāng)然,這聽起來有些愚蠢,但它是可能的,而編寫 C++ 解析器的人必須考慮所有可能的輸入,甚至是愚蠢的。

              直到 C 成為已知之前,沒有任何辦法知道 C::const_iterator 到底是不是一個(gè) type(類型),而當(dāng) template(模板)print2nd 被解析的時(shí)候,C 還不是已知的。C++ 有一條規(guī)則解決這個(gè)歧義:如果解析器在一個(gè) template(模板)中遇到一個(gè) nested dependent name(嵌套依賴名字),它假定那個(gè)名字不是一個(gè) type(類型),除非你用其它方式告訴它。缺省情況下,nested dependent name(嵌套依賴名字)不是 types(類型)。(對于這條規(guī)則有一個(gè)例外,我待會兒告訴你。)

              記住這個(gè),再看看 print2nd 的開頭:
            template<typename C>
            void print2nd(const C& container)
            {
             
            if (container.size() >= 2) {
              C::const_iterator iter(container.begin()); 
            // this name is assumed to
               // not be a type
              這為什么不是合法的 C++ 現(xiàn)在應(yīng)該很清楚了。iter 的 declaration(聲明)僅僅在 C::const_iterator 是一個(gè) type(類型)時(shí)才有意義,但是我們沒有告訴 C++ 它是,而 C++ 就假定它不是。要想轉(zhuǎn)變這個(gè)形勢,我們必須告訴 C++ C::const_iterator 是一個(gè) type(類型)。我們將 typename 放在緊挨著它的前面來做到這一點(diǎn):
            template<typename C> // this is valid C++
            void print2nd(const C& container)
            {
            if (container.size() >= 2) {
            typename C::const_iterator iter(container.begin());

            }
            }
              通用的規(guī)則很簡單:在你涉及到一個(gè)在 template(模板)中的 nested dependent type name(嵌套依賴類型名)的任何時(shí)候,你必須把單詞 typename 放在緊挨著它的前面。(重申一下,我待會兒要描述一個(gè)例外。)

              typename 應(yīng)該僅僅被用于標(biāo)識 nested dependent type name(嵌套依賴類型名);其它名字不應(yīng)該用它。例如,這是一個(gè)取得一個(gè) container(容器)和這個(gè) container(容器)中的一個(gè) iterator(迭代器)的 function template(函數(shù)模板):
            template<typename C> // typename allowed (as is "class")
            void f(const C& container, // typename not allowed
            typename C::iterator iter); // typename required
              C 不是一個(gè) nested dependent type name(嵌套依賴類型名)(它不是嵌套在依賴于一個(gè) template parameter(模板參數(shù))的什么東西內(nèi)部的),所以在聲明 container 時(shí)它不必被 typename 前置,但是 C::iterator 是一個(gè) nested dependent type name(嵌套依賴類型名),所以它必需被 typename 前置。

              "typename must precede nested dependent type names"(“typename 必須前置于嵌套依賴類型名”)規(guī)則的例外是 typename 不必前置于在一個(gè) list of base classes(基類列表)中的或者在一個(gè) member initialization list(成員初始化列表)中作為一個(gè) base classes identifier(基類標(biāo)識符)的 nested dependent type name(嵌套依賴類型名)。例如:
            template<typename T>
            class Derived: public Base<T>::Nested { 
             
            // base class list: typename not
             public// allowed
              explicit Derived(int x)
              : Base
            <T>::Nested(x) // base class identifier in mem
              { 
               
            // init. list: typename not allowed
             
               typename Base
            <T>::Nested temp; // use of nested dependent type
                // name not in a base class list or
              } // as a base class identifier in a
               // mem. init. list: typename required
            };
              這樣的矛盾很令人討厭,但是一旦你在經(jīng)歷中獲得一點(diǎn)經(jīng)驗(yàn),你幾乎不會在意它。

              讓我們來看最后一個(gè) typename 的例子,因?yàn)樗谀憧吹降恼鎸?shí)代碼中具有代表性。假設(shè)我們在寫一個(gè)取得一個(gè) iterator(迭代器)的 function template(函數(shù)模板),而且我們要做一個(gè) iterator(迭代器)指向的 object(對象)的局部拷貝 temp,我們可以這樣做:
            template<typename IterT>
            void workWithIterator(IterT iter)
            {
             typename std::iterator_traits
            <IterT>::value_type temp(*iter);
             
            }
              不要讓 std::iterator_traits<IterT>::value_type 嚇倒你。那僅僅是一個(gè) standard traits class(標(biāo)準(zhǔn)特性類)的使用,用 C++ 的說法就是 "the type of thing pointed to by objects of type IterT"(“被類型為 IterT 的對象所指向的東西的類型”)。這個(gè)語句聲明了一個(gè)與 IterT objects 所指向的東西類型相同的 local variable(局部變量)(temp),而且用 iter 所指向的 object(對象)對 temp 進(jìn)行了初始化。如果 IterT 是 vector<int>::iterator,temp 就是 int 類型。如果 IterT 是 list<string>::iterator,temp 就是 string 類型。因?yàn)?std::iterator_traits<IterT>::value_type 是一個(gè) nested dependent type name(嵌套依賴類型名)(value_type 嵌套在 iterator_traits<IterT> 內(nèi)部,而且 IterT 是一個(gè) template parameter(模板參數(shù))),我們必須讓它被 typename 前置。

              如果你覺得讀 std::iterator_traits<IterT>::value_type 令人討厭,就想象那個(gè)與它相同的東西來代表它。如果你像大多數(shù)程序員,對多次輸入它感到恐懼,那么你就需要創(chuàng)建一個(gè) typedef。對于像 value_type 這樣的 traits member names(特性成員名),一個(gè)通用的慣例是 typedef name 與 traits member name 相同,所以這樣的一個(gè) local typedef 通常定義成這樣:
            template<typename IterT>
            void workWithIterator(IterT iter)
            {
             typedef typename std::iterator_traits
            <IterT>::value_type value_type;

             value_type temp(
            *iter);
             
            }
              很多程序員最初發(fā)現(xiàn) "typedef typename" 并列不太和諧,但它是涉及 nested dependent type names(嵌套依賴類型名)規(guī)則的一個(gè)合理的附帶結(jié)果。你會相當(dāng)快地習(xí)慣它。你畢竟有著強(qiáng)大的動機(jī)。你輸入 typename std::iterator_traits<IterT>::value_type 需要多少時(shí)間?

              作為結(jié)束語,我應(yīng)該提及編譯器與編譯器之間對圍繞 typename 的規(guī)則的執(zhí)行情況的不同。一些編譯器接受必需 typename 時(shí)它卻缺失的代碼;一些編譯器接受不許 typename 時(shí)它卻存在的代碼;還有少數(shù)的(通常是老舊的)會拒絕 typename 出現(xiàn)在它必需出現(xiàn)的地方。這就意味著 typename 和 nested dependent type names(嵌套依賴類型名)的交互作用會導(dǎo)致一些輕微的可移植性問題。

              Things to Remember

              ·在聲明 template parameters(模板參數(shù))時(shí),class 和 typename 是可互換的。

              ·用 typename 去標(biāo)識 nested dependent type names(嵌套依賴類型名),在 base class lists(基類列表)中或在一個(gè) member initialization list(成員初始化列表)中作為一個(gè) base class identifier(基類標(biāo)識符)時(shí)除外。

            posted @ 2007-04-16 15:27 安帛偉 閱讀(444) | 評論 (0)編輯 收藏

            為了使用hash_map,今天下載了STLport,在VC6下編譯成功。

            1. STLport下載:http://www.stlport.org/
                  我下載的是最新版  02.25.07: STLport 5.1.2 released

            2. STLport編譯:
                  我的STLport目錄是:D:\STLport-5.1.2
                  先設(shè)置一下VC6下的環(huán)境變量:C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT
                 把D:\STLport-5.1.2\stlport;加入Include路徑中;把D:\STLport-5.1.2\lib;加入Lib路徑中
                  在命令行窗口下:
                  運(yùn)行VCVARS32.BAT,然后
                  cd D:\STLport-5.1.2\build\lib
                  configure -c msvc6
                  nmake /fmsvc.mak install
                  編譯全部用的默認(rèn)選項(xiàng),因此編譯出來的是多線程靜態(tài)鏈接庫。庫文件被拷貝到D:\STLport-5.1.2\lib

            3. 在VC6中使用STLport:
                  Tools->Options...->Directories中
                  include設(shè)置中添加目錄:D:\STLport-5.1.2\stlport
                  library設(shè)置中添加目錄:D:\STLport-5.1.2\lib
                  Project->Settings...->C/C++中
                  Category選擇Code Generation,然后在use run-time library中選擇Debug Multithreaded。(如果是release版本,選擇Multithreaded;如果想用動態(tài)鏈接,則要先編譯動態(tài)鏈接版本的STLport,再在這兒選擇相應(yīng)的DLL)

            4. hash_map的例子:
            #include <iostream>
            #include 
            <hash_map>
            #include 
            <string>

            using namespace std;

            int main()
            {
                hash_map
            <intstring> mymap;
                mymap[
            2008]="VC6";
                mymap[
            999999]="STLport";
                mymap[
            123456]="hello hash_map!";
                hash_map
            <intstring>::iterator iter = mymap.find(123456);
                
            if(iter != mymap.end())
                
            {
                    cout
            <<iter->second<<endl;
                }

                
            return 0;
            }

            posted @ 2007-04-16 14:22 安帛偉 閱讀(8402) | 評論 (21)編輯 收藏

            現(xiàn)在在 Visual C++ Toolkit 2003 的主頁上,下載鏈接已經(jīng)被去掉,轉(zhuǎn)而勸告人們使用 Visual C++ 2005 Express。
            VCToolkitSetup.exe

            下載

            http://xona.com/programs/VCToolkitSetup%28v1.01%29%282004.07.06%29.zip
            MD5: 90D8B963CA196AA9855B2CA6C3174C14
            posted @ 2007-04-13 17:05 安帛偉 閱讀(4286) | 評論 (6)編輯 收藏

            我們在編寫應(yīng)用程序的時(shí)候explicit關(guān)鍵字基本上是很少使用,它的作用是"禁止單參數(shù)構(gòu)造函數(shù)"被用于自動型別轉(zhuǎn)換,其中比較典型的例子就是容器類型,在這種類型的構(gòu)造函數(shù)中你可以將初始長度作為參數(shù)傳遞給構(gòu)造函數(shù).
            例如:
            你可以聲明這樣一個(gè)構(gòu)造函數(shù)

            class Array
            {
            public:
             
            explicit Array(int size);
             
            //
            }
            ;
            在這里explicit關(guān)鍵字起著至關(guān)重要的作用,如果沒有這個(gè)關(guān)鍵字的話,這個(gè)構(gòu)造函數(shù)有能力將int轉(zhuǎn)換成Array.一旦這種情況發(fā)生,你可以給Array支派一個(gè)整數(shù)值而不會引起任何的問題,比如:
            Array arr;
            //
            arr = 40;
            此時(shí),C++的自動型別轉(zhuǎn)換會把40轉(zhuǎn)換成擁有40個(gè)元素的Array,并且指派給arr變量,這個(gè)結(jié)果根本就不是我們想要的結(jié)果.如果我們將構(gòu)造函數(shù)聲明為explicit,上面的賦值操作就會導(dǎo)致編譯器報(bào)錯,使我們可以及時(shí)發(fā)現(xiàn)錯誤.
            需要注意的是:explicit同樣也能阻止"以賦值語法進(jìn)行帶有轉(zhuǎn)型操作的初始化";
            例如:
            Array arr(40);//正確
            Array arr = 40;//錯誤 
            看一下以下兩種操作:
            X x;
            Y y(x);
            //顯式類型轉(zhuǎn)換
            另一種
            X x;
            Y y 
            = x;//隱式類型轉(zhuǎn)換
            這兩種操作存在一個(gè)小小的差別,第一種方式式通過顯式類型轉(zhuǎn)換,根據(jù)型別x產(chǎn)生了型別Y的新對象;第二種方式通過隱式轉(zhuǎn)換產(chǎn)生了一個(gè)型別Y的新對象.
            explicit關(guān)鍵字的應(yīng)用主要就是上面所說的構(gòu)造函數(shù)定義中,參考該關(guān)鍵字的應(yīng)用可以看看STL源代碼,其中大量使用了該關(guān)鍵字
            posted @ 2007-04-12 11:09 安帛偉 閱讀(388) | 評論 (0)編輯 收藏

            關(guān)鍵字mutable是C++中一個(gè)不常用的關(guān)鍵字,他只能用于類的非靜態(tài)和非常量數(shù)據(jù)成員
            我們知道一個(gè)對象的狀態(tài)由該對象的非靜態(tài)數(shù)據(jù)成員決定,所以隨著數(shù)據(jù)成員的改變,
            對像的狀態(tài)也會隨之發(fā)生變化!
            如果一個(gè)類的成員函數(shù)被聲明為const類型,表示該函數(shù)不會改變對象的狀態(tài),也就是
            該函數(shù)不會修改類的非靜態(tài)數(shù)據(jù)成員.但是有些時(shí)候需要在該類函數(shù)中對類的數(shù)據(jù)成員
            進(jìn)行賦值.這個(gè)時(shí)候就需要用到mutable關(guān)鍵字了

            例如:

            class Demo
            {
            public:
                Demo()
            {}
                
            ~Demo(){}
            public:
                
            bool getFlag() const
                
            {
                    m_nAccess
            ++;
                    
            return m_bFlag;
                }

            private:
                
            int  m_nAccess;
                
            bool m_bFlag;
            }


            int main()
            {
                
            return 0;
            }
             


            編譯上面的代碼會出現(xiàn) error C2166: l-value specifies const object的錯誤
            說明在const類型的函數(shù)中改變了類的非靜態(tài)數(shù)據(jù)成員.

            這個(gè)時(shí)候需要使用mutable來修飾一下要在const成員函數(shù)中改變的非靜態(tài)數(shù)據(jù)成員
            m_nAccess,代碼如下:

            class Demo
            {
            public:
                Demo()
            {}
                
            ~Demo(){}
            public:
                
            bool getFlag() const
                
            {
                    m_nAccess
            ++;
                    
            return m_bFlag;
                }

            private:
                mutable 
            int  m_nAccess;
                
            bool m_bFlag;
            }


            int main()
            {
                
            return 0;
            }
             

            這樣再重新編譯的時(shí)候就不會出現(xiàn)錯誤了!
            posted @ 2007-04-12 10:50 安帛偉 閱讀(314) | 評論 (0)編輯 收藏

            工廠方法和抽象工廠實(shí)際上是從不同角度在描述問題。
            工廠方法描述了具體產(chǎn)品的創(chuàng)建,而抽象工廠描述的是產(chǎn)品系列的組織。

            // ?Computer.cpp?:?Defines?the?entry?point?for?the?console?application.
            //

            #include?
            " stdafx.h "
            #include?
            < string >
            #include?
            < iostream >

            using ? namespace ?std;

            class ?Ram {} ;
            class ?IBMRam:? public ?Ram {} ;
            class ?HPRam:? public ?Ram {} ;
            class ?Cpu {} ;
            class ?IBMCpu:? public ?Cpu {} ;
            class ?HPCpu:? public ?Cpu {} ;

            class ?Computer
            {
            public :
            ?Computer(
            string ?strName,?Ram * ?pRam,?Cpu * ?pCpu)
            ?
            {
            ??m_strName?
            = ?strName;
            ??m_pRam?
            = ?pRam;
            ??m_pCpu?
            = ?pCpu;
            ??cout
            << " A? " << ?m_strName? << " ?computer?is?produced " << endl;
            ?}

            ?
            ~ Computer()
            ?
            {
            ??delete?m_pRam;
            ??delete?m_pCpu;
            ??cout
            << " A? " << ?m_strName? << " ?computer?is?deleted " << endl;
            ?}

            public :
            ?
            string ?m_strName;
            private :
            ?Ram
            * ?m_pRam;
            ?Cpu
            * ?m_pCpu;
            }
            ;

            class ?ComputerProducer
            {
            public :
            ?Computer
            * ?createComputer()
            ?
            {
            ??
            return ? new ?Computer(setName(),?createRam(),?createCpu());
            ?}

            ?
            virtual ?Ram * ?createRam()? = ? 0 ;
            ?
            virtual ?Cpu * ?createCpu()? = ? 0 ;
            ?
            virtual ? string ?setName()? = ? 0 ;
            }
            ;

            class ?IBMProducer:? public ?ComputerProducer
            {
            public :
            ?
            virtual ?Ram * ?createRam()
            ?
            {
            ??cout
            << " A?IBMRam?is?producted " << endl;
            ??
            return ? new ?IBMRam;
            ?}

            ?
            virtual ?Cpu * ?createCpu()
            ?
            {
            ??cout
            << " A?IBMCPU?is?producted " << endl;
            ??
            return ? new ?IBMCpu;
            ?}

            ?
            virtual ? string ?setName()
            ?
            {
            ??
            return ? string ( " IBM " );
            ?}

            }
            ;

            class ?HPProducer:? public ?ComputerProducer
            {
            public :
            ?
            virtual ?Ram * ?createRam()
            ?
            {
            ??cout
            << " A?HPRam?is?producted " << endl;
            ??
            return ? new ?HPRam;
            ?}

            ?
            virtual ?Cpu * ?createCpu()
            ?
            {
            ??cout
            << " A?HPCPU?is?producted " << endl;
            ??
            return ? new ?HPCpu;
            ?}

            ?
            virtual ? string ?setName()
            ?
            {
            ??
            return ? string ( " HP " );
            ?}

            }
            ;

            int ?main( int ?argc,? char * ?argv[])
            {
            ?
            // ?client?code
            ?ComputerProducer * ?pIBMFac = ? new ?IBMProducer;
            ?ComputerProducer
            * ?pHPFac? = ? new ?HPProducer;
            ?Computer
            * ?pIBMComputer? = ?pIBMFac -> createComputer();
            ?Computer
            * ?pHPComputer? = ?pHPFac? -> createComputer();
            ?delete?pIBMComputer;
            ?delete?pHPComputer;
            ?delete?pIBMFac;
            ?delete?pHPFac;
            ?
            return ? 0 ;
            }


            這個(gè)例子比較清楚了,不同的工廠生產(chǎn)不同的計(jì)算機(jī),但計(jì)算機(jī)的基本組成(這里假設(shè)計(jì)算機(jī)僅由ram和cpu組成)是一樣的,這樣的產(chǎn)品系列很適合用抽象工廠來組織。
            而在實(shí)際生產(chǎn)計(jì)算機(jī)的時(shí)候,createRam()和createCpu()這兩個(gè)工廠方法又起到了作用。

            posted @ 2007-03-25 23:20 安帛偉 閱讀(1108) | 評論 (0)編輯 收藏

            僅列出標(biāo)題
            共3頁: 1 2 3 
            国产精品日韩欧美久久综合| 日韩乱码人妻无码中文字幕久久| 国产一区二区精品久久岳| 99久久久久| 久久婷婷午色综合夜啪| 亚洲国产精品一区二区久久hs| 无码精品久久久天天影视| 1000部精品久久久久久久久| 99久久国产热无码精品免费久久久久| 久久国产影院| 亚洲乱码精品久久久久.. | 久久久久久夜精品精品免费啦| 国产亚洲综合久久系列| 国产午夜精品理论片久久 | 91精品观看91久久久久久| 久久久久亚洲精品男人的天堂| 久久人妻无码中文字幕| 色偷偷888欧美精品久久久| 久久精品久久久久观看99水蜜桃 | 国产精品青草久久久久婷婷 | 国产毛片欧美毛片久久久| 亚洲国产精品久久久久网站| 亚洲精品无码久久毛片 | 欧美精品国产综合久久| 久久精品中文字幕久久| 久久无码中文字幕东京热| 国产精品无码久久久久| 久久久久久亚洲精品成人| 中文字幕久久精品| 国产成人精品久久| 99久久er这里只有精品18| 一本久久精品一区二区| 国产精品亚洲综合专区片高清久久久| 一本色道久久综合狠狠躁| 日韩一区二区三区视频久久| 日本道色综合久久影院| 久久久久亚洲av无码专区导航| 久久青青色综合| 人人狠狠综合88综合久久| 久久99热这里只有精品国产| 国产精品一久久香蕉国产线看 |