日韩精品一区二区三区在线视频放-无码中文字幕V?一区二区-成年片免费观看视频-国内少妇人妻丰满av-国产精品中文字幕免费观看-亚洲成人久久一区二区三区-国内少妇偷人精品视频无缓冲-一区二区国产精品日本一区二区三区在线网

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營的一線實(shí)戰(zhàn)洞察。

C++模板類聲明與實(shí)現(xiàn)分離:三種策略深度解析與實(shí)戰(zhàn)

C++模板類聲明與實(shí)現(xiàn)分離:三種策略深度解析與實(shí)戰(zhàn) 1. 項目概述為什么要把模板類的“皮”和“肉”分開如果你寫過C模板類尤其是稍微復(fù)雜一點(diǎn)的十有八九都遇到過那個經(jīng)典的鏈接錯誤undefined reference to Stackint::push(int const)。編譯器在編譯用到Stackint的main.cpp時它看到了模板的聲明知道有push這個方法但就是找不到這個方法的“肉身”在哪。這感覺就像你拿到了一份功能強(qiáng)大的產(chǎn)品說明書頭文件但關(guān)鍵的零部件實(shí)現(xiàn)代碼卻不在同一個包裹里工廠鏈接器自然沒法把產(chǎn)品組裝出來。這就是我們今天要徹底搞明白的核心問題如何優(yōu)雅地定義C模板并把它的類定義聲明和類實(shí)現(xiàn)定義分離開來。很多人包括一些有經(jīng)驗(yàn)的開發(fā)者都習(xí)慣把模板的所有代碼一股腦塞進(jìn)頭文件.h或.hpp里。這當(dāng)然能工作但它帶來了幾個頭疼的問題編譯時間爆炸式增長因?yàn)槊總€包含該頭文件的.cpp文件都要重新實(shí)例化一遍模板、代碼結(jié)構(gòu)混亂聲明和實(shí)現(xiàn)攪在一起以及最關(guān)鍵的——它模糊了傳統(tǒng)C“聲明放.h實(shí)現(xiàn)放.cpp”的良好工程實(shí)踐。以我們最熟悉的“?!睘槔Y(jié)構(gòu)清晰操作明確push, pop, top, empty是理解模板分離機(jī)制的絕佳模型。通過實(shí)現(xiàn)一個分離的模板棧你不僅能掌握解決上述鏈接錯誤的方法更能深入理解C模板的實(shí)例化機(jī)制、顯式實(shí)例化的威力以及如何組織大型模板庫的代碼結(jié)構(gòu)。這對于編寫可復(fù)用、易維護(hù)、編譯高效的C庫至關(guān)重要也是邁向高級C開發(fā)的必經(jīng)之路。2. 核心原理模板的“兩次編譯”與分離困境要解決問題得先理解問題是怎么來的。C模板的工作機(jī)制和普通類有本質(zhì)區(qū)別這導(dǎo)致了它們“分家”特別困難。2.1 普通類的編譯鏈接模型對于普通類比如一個PlainStack非模板流程非常清晰聲明在頭文件(plainstack.h)這里只有類藍(lán)圖和方法原型。// plainstack.h class PlainStack { public: void push(int value); int top() const; // ... 其他聲明 private: int data[100]; int index; };實(shí)現(xiàn)在源文件(plainstack.cpp)這里給出方法的具體實(shí)現(xiàn)。// plainstack.cpp #include plainstack.h void PlainStack::push(int value) { data[index] value; } int PlainStack::top() const { return data[index-1]; }編譯階段編譯器分別編譯main.cpp和plainstack.cpp生成目標(biāo)文件.o。在編譯main.cpp時它只需要看到plainstack.h中的聲明知道push和top長什么樣函數(shù)簽名至于它們具體怎么做編譯器暫時不關(guān)心。鏈接階段鏈接器登場它的任務(wù)就是把main.o里對PlainStack::push和PlainStack::top的“調(diào)用請求”與plainstack.o里這兩個函數(shù)的“實(shí)際地址”連接起來。一旦找到程序就能運(yùn)行。這個模型的核心是分離編譯接口和實(shí)現(xiàn)分離各自獨(dú)立編譯最后再由鏈接器組裝。這極大地提高了編譯效率修改實(shí)現(xiàn)文件只需重新編譯該文件本身。2.2 模板類的“兩次編譯”困境模板類StackT就完全不同了。它不是一個具體的類而是一個“類工廠”的配方。編譯器需要根據(jù)你使用的具體類型比如Stackint,Stackstd::string來現(xiàn)場生成對應(yīng)的類。這個過程叫做實(shí)例化。關(guān)鍵在于實(shí)例化發(fā)生在編譯階段而不是鏈接階段。當(dāng)編譯器在main.cpp中看到Stackint intStack;時它必須立刻知道如何生成Stackint這個具體類的所有方法push(int),pop(), 等等。如果這些方法的實(shí)現(xiàn)定義在另一個.cpp文件里而編譯器在編譯main.cpp時沒有看到它們那它就沒辦法生成代碼。到了鏈接階段鏈接器發(fā)現(xiàn)main.o需要Stackint::push的代碼但翻遍所有.o文件都找不到——因?yàn)閟tack.cpp里只有模板的“配方”泛型代碼沒有生成任何具體的Stackint代碼。這就是“undefined reference”錯誤的根源。所以傳統(tǒng)的.h聲明 .cpp實(shí)現(xiàn)模式對模板行不通因?yàn)閷?shí)現(xiàn)代碼在編譯main.cpp時不可見。注意這里常有一個誤解認(rèn)為“模板不能分離編譯”。更準(zhǔn)確的說法是模板的聲明和定義必須在同一個翻譯單元通常就是一個.cpp文件及其包含的所有頭文件中對編譯器可見才能成功實(shí)例化。我們接下來的所有技巧都是圍繞如何滿足這個條件而展開的。3. 方案選型三種主流分離策略的深度對比既然知道了問題的癥結(jié)在于“編譯器在需要的時候看不到實(shí)現(xiàn)”那么解決方案就是想辦法讓編譯器看到。主要有三種主流策略各有優(yōu)劣適用于不同場景。3.1 方案一包含模式 (The Inclusion Model) —— 最簡單直接這是最常見、也是新手最該先掌握的方法。顧名思義就是把模板的實(shí)現(xiàn)也直接寫在頭文件里。具體做法 創(chuàng)建一個頭文件例如stack.hpp用.hpp后綴來暗示這是包含實(shí)現(xiàn)的模板頭文件是個好習(xí)慣里面同時包含類聲明和所有成員函數(shù)的定義。代碼結(jié)構(gòu)// stack.hpp #ifndef STACK_HPP #define STACK_HPP #include vector #include stdexcept // 用于 std::underflow_error template typename T class Stack { public: bool empty() const; void push(const T item); void pop(); T top(); const T top() const; // 提供const版本用于const對象 private: std::vectorT elems; }; // ---------- 成員函數(shù)定義實(shí)現(xiàn)直接跟在后面 ---------- template typename T bool StackT::empty() const { return elems.empty(); } template typename T void StackT::push(const T item) { elems.push_back(item); } template typename T void StackT::pop() { if (elems.empty()) { throw std::underflow_error(Stack::pop(): empty stack); } elems.pop_back(); } template typename T T StackT::top() { if (elems.empty()) { throw std::underflow_error(Stack::top(): empty stack); } return elems.back(); } template typename T const T StackT::top() const { // 重載const版本代碼邏輯相同但返回const引用 if (elems.empty()) { throw std::underflow_error(Stack::top() const: empty stack); } return elems.back(); } #endif // STACK_HPP使用方式在main.cpp中直接#include stack.hpp即可。優(yōu)點(diǎn)零學(xué)習(xí)成本絕對可靠完全符合C標(biāo)準(zhǔn)永遠(yuǎn)不會出現(xiàn)鏈接錯誤。簡單明了所有代碼都在一個文件里查看和修改都方便。缺點(diǎn)編譯時間慢這是最致命的缺點(diǎn)。如果這個模板頭文件被幾十個.cpp文件包含那么模板代碼就會被編譯幾十次。如果模板實(shí)現(xiàn)很復(fù)雜比如一個龐大的矩陣運(yùn)算庫這將嚴(yán)重拖慢整個項目的編譯速度。暴露實(shí)現(xiàn)細(xì)節(jié)你不得不將所有的實(shí)現(xiàn)細(xì)節(jié)包括引用的其他頭文件、使用的內(nèi)部數(shù)據(jù)結(jié)構(gòu)暴露給用戶。這破壞了封裝性也使得用戶代碼可能因?yàn)槟愕膶?shí)現(xiàn)細(xì)節(jié)而意外編譯失敗例如你的實(shí)現(xiàn)里用了#include algorithm用戶代碼可能并不需要知道這個。適用場景小型項目、模板代碼量不大、或者對編譯時間不敏感的原型開發(fā)階段。3.2 方案二顯式實(shí)例化 (Explicit Instantiation) —— 平衡之道這是真正實(shí)現(xiàn)“聲明與實(shí)現(xiàn)分離”的標(biāo)準(zhǔn)方法。我們回歸傳統(tǒng)的.h和.cpp文件結(jié)構(gòu)但在.cpp文件的末尾明確告訴編譯器“請為我生成這些特定類型的模板實(shí)例”。具體做法頭文件 (stack.h)只包含模板的聲明。// stack.h #ifndef STACK_H #define STACK_H #include vector #include stdexcept template typename T class Stack { public: bool empty() const; void push(const T item); void pop(); T top(); const T top() const; private: std::vectorT elems; }; #endif // STACK_H實(shí)現(xiàn)文件 (stack.cpp)包含成員函數(shù)的定義并在文件末尾進(jìn)行顯式實(shí)例化。// stack.cpp #include stack.h // 成員函數(shù)定義 template typename T bool StackT::empty() const { /* 實(shí)現(xiàn)同上 */ } template typename T void StackT::push(const T item) { /* 實(shí)現(xiàn)同上 */ } // ... 其他成員函數(shù)定義 // 關(guān)鍵部分顯式實(shí)例化 template class Stackint; // 告訴編譯器請生成int版本的Stack template class Stackdouble; // 告訴編譯器請生成double版本的Stack template class Stackstd::string; // 告訴編譯器請生成std::string版本的Stack // 你可以在這里列出所有你預(yù)計會使用的類型使用在main.cpp中#include stack.h。編譯時必須將stack.cpp一起編譯例如g main.cpp stack.cpp -o prog。工作原理編譯stack.cpp時編譯器看到了模板的全部定義以及template class Stackint;這條指令于是它為Stackint生成了所有成員函數(shù)的二進(jìn)制代碼并存入stack.o。鏈接時main.o中對Stackint方法的調(diào)用就能在stack.o中找到定義了。優(yōu)點(diǎn)真正的分離完美實(shí)現(xiàn)了接口(.h)與實(shí)現(xiàn)(.cpp)的分離。編譯加速模板代碼只在stack.cpp中被編譯一次。其他文件包含輕量級的stack.h編譯極快。隱藏實(shí)現(xiàn)用戶只需要看到簡潔的聲明頭文件。缺點(diǎn)靈活性受限這是最大的代價。你必須在stack.cpp中預(yù)先知道并列出所有可能用到的類型。如果用戶想在項目中使用一個你沒列出的類型比如StackMyCustomClass鏈接器會報“undefined reference”錯誤因?yàn)榫幾g器從未為這個類型生成代碼。維護(hù)負(fù)擔(dān)每當(dāng)需要支持一個新類型你都必須去修改stack.cpp文件添加一行新的顯式實(shí)例化語句并重新編譯該文件。適用場景模板需要支持的類型集合是已知的、有限的并且穩(wěn)定不變。例如一個數(shù)學(xué)庫中的Vector2/3/4模板通常只實(shí)例化float和double類型。許多大型商業(yè)庫如某些版本的Boost內(nèi)部會采用這種方式來預(yù)編譯常用類型以提升用戶編譯速度。3.3 方案三分離編譯模式 (The Separation Model) —— 使用export已廢棄或替代技巧C標(biāo)準(zhǔn)曾經(jīng)引入export關(guān)鍵字意圖讓模板能像普通函數(shù)一樣聲明和定義分離。但因?yàn)樗鼘?shí)現(xiàn)難度極大只有極少數(shù)編譯器如EDG支持且最終被C11標(biāo)準(zhǔn)標(biāo)記為廢棄在C17中正式移除。所以絕對不要在你的新項目中使用export。那么有沒有辦法模擬“分離編譯”呢有但本質(zhì)上是方案一的變體。我們可以通過額外的包含技巧來保持視覺上的分離。具體做法創(chuàng)建聲明頭文件stack.h同方案二。創(chuàng)建實(shí)現(xiàn)文件stack.ipp或stack.impl.h注意后綴名表示這是要被包含的實(shí)現(xiàn)。// stack.ipp (或 stack_impl.h) #ifndef STACK_IPP #define STACK_IPP // 注意這里不直接包含stack.h假設(shè)調(diào)用者已經(jīng)包含了 template typename T bool StackT::empty() const { /* 實(shí)現(xiàn) */ } // ... 其他實(shí)現(xiàn) #endif // STACK_IPP在聲明頭文件stack.h的末尾有條件地包含實(shí)現(xiàn)文件。// stack.h (末尾部分) // ... 類聲明 #ifdef STACK_IMPLEMENTATION #include stack.ipp #endif #endif // STACK_H使用方式有兩種方式A常用用戶在一個統(tǒng)一的“匯聚點(diǎn)”比如一個專門的implement.cpp中定義STACK_IMPLEMENTATION宏然后包含stack.h。這樣整個項目中模板只在此處被實(shí)例化一次。// implement.cpp #define STACK_IMPLEMENTATION #include stack.h方式B在stack.h中直接取消條件編譯最后一行就是#include stack.ipp。這本質(zhì)上又變回了方案一但文件在邏輯上是分開的。優(yōu)點(diǎn)邏輯清晰在代碼管理上聲明和實(shí)現(xiàn)仍然是獨(dú)立的文件??煽氐木幾g次數(shù)通過方式A可以精確控制模板在哪個源文件中被實(shí)例化從而管理編譯依賴。缺點(diǎn)并未真正解決包含模式的本質(zhì)問題如果采用方式B或者用戶不小心在多個文件中定義了STACK_IMPLEMENTATION依然會導(dǎo)致多次編譯。它更像是一種代碼組織風(fēng)格。適用場景中大型項目希望保持代碼文件分離的整潔性同時又愿意接受方案一的內(nèi)在限制或者希望通過一個中心文件來管理所有模板實(shí)例化。方案對比總結(jié)表特性包含模式 (Inclusion)顯式實(shí)例化 (Explicit Instantiation)分離包含模式 (Inclusion with .ipp)代碼分離否同文件是(.h/.cpp)是邏輯分離物理包含編譯速度慢N次編譯快1次編譯取決于用法可能慢或快使用靈活性高支持任何類型低僅預(yù)定義類型高支持任何類型實(shí)現(xiàn)隱藏否是否標(biāo)準(zhǔn)符合性完全符合完全符合完全符合本質(zhì)是包含推薦場景小型項目、通用庫、原型類型固定的庫、追求編譯速度注重代碼文件組織的中大型項目4. 實(shí)戰(zhàn)演練構(gòu)建一個可分離編譯的健壯棧模板理論說再多不如動手寫一遍。我們選擇**方案二顯式實(shí)例化**作為實(shí)戰(zhàn)案例因?yàn)樗钅荏w現(xiàn)“分離”的精髓并且能讓我們深入理解背后的機(jī)制。我們會構(gòu)建一個工業(yè)級強(qiáng)度的Stack模板。4.1 項目結(jié)構(gòu)與文件規(guī)劃首先規(guī)劃我們的項目目錄結(jié)構(gòu)良好的結(jié)構(gòu)是成功的一半。your_project/ ├── include/ # 對外公開的頭文件接口 │ └── stack.h ├── src/ # 私有源文件實(shí)現(xiàn) │ └── stack.cpp └── apps/ # 示例或測試程序 └── main.cpp4.2 接口設(shè)計include/stack.h頭文件是類的門面設(shè)計要清晰、健壯、易于使用。// include/stack.h #ifndef MYLIB_STACK_H // 使用包含項目名的宏防止沖突 #define MYLIB_STACK_H #include cstddef // for std::size_t namespace mylib { // 放入自定義命名空間避免污染全局 /** * brief 一個基于模板的通用棧容器。 * * tparam T 棧中元素的類型。 * tparam Container 底層容器類型默認(rèn)為 std::vectorT。 * 必須提供 back(), push_back(), pop_back(), empty() 接口。 */ template typename T, typename Container std::vectorT class Stack { public: using value_type T; using container_type Container; using size_type typename Container::size_type; using reference typename Container::reference; using const_reference typename Container::const_reference; // 構(gòu)造函數(shù) Stack() default; explicit Stack(const Container cont) : c(cont) {} explicit Stack(Container cont) : c(std::move(cont)) {} // 容量相關(guān) bool empty() const noexcept { return c.empty(); } size_type size() const noexcept { return c.size(); } // 元素訪問 reference top() { check_empty(); return c.back(); } const_reference top() const { check_empty(); return c.back(); } // 修改器 void push(const value_type value) { c.push_back(value); } void push(value_type value) { c.push_back(std::move(value)); } templatetypename... Args void emplace(Args... args) { c.emplace_back(std::forwardArgs(args)...); } void pop() { check_empty(); c.pop_back(); } void swap(Stack other) noexcept(noexcept(std::swap(c, other.c))) { using std::swap; swap(c, other.c); } // 比較運(yùn)算符非成員函數(shù)在類外聲明為友元或單獨(dú)實(shí)現(xiàn) // 為簡潔起見此處省略實(shí)際庫中應(yīng)考慮實(shí)現(xiàn)。 private: Container c; // 底層容器 void check_empty() const { if (empty()) { throw std::underflow_error(Stack::top/pop: empty stack); } } }; // 非成員函數(shù) swap 的重載用于支持 ADL (Argument-Dependent Lookup) template typename T, typename Container void swap(StackT, Container lhs, StackT, Container rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } } // namespace mylib #endif // MYLIB_STACK_H設(shè)計要點(diǎn)解析命名空間mylib將我們的代碼與標(biāo)準(zhǔn)庫及其他庫隔離開。模板參數(shù)除了元素類型T還增加了Container參數(shù)默認(rèn)為std::vectorT。這遵循了標(biāo)準(zhǔn)庫適配器如std::stack的設(shè)計提供了靈活性未來可輕松切換為std::deque或std::list。類型別名using語句定義了標(biāo)準(zhǔn)容器風(fēng)格的類型別名提高了代碼的可讀性和通用性。構(gòu)造函數(shù)提供了默認(rèn)構(gòu)造、拷貝底層容器和移動底層容器的構(gòu)造函數(shù)。explicit防止了意外的隱式轉(zhuǎn)換。異常安全noexcept修飾符正確標(biāo)識了不會拋出異常的函數(shù)如empty(),size()有助于編譯器優(yōu)化。元素訪問安全top()和pop()在操作前會調(diào)用私有方法check_empty()檢查棧狀態(tài)避免未定義行為拋出標(biāo)準(zhǔn)的std::underflow_error異常?,F(xiàn)代C支持提供了右值引用版本的push和emplace方法支持高效地放置新元素。swap操作提供了成員函數(shù)和非成員函數(shù)版本的swap并正確使用noexcept規(guī)范符合標(biāo)準(zhǔn)庫容器的慣例。4.3 實(shí)現(xiàn)分離src/stack.cpp這是顯式實(shí)例化的核心。我們將所有成員函數(shù)的定義放在這里并在末尾列出需要預(yù)編譯的類型。// src/stack.cpp #include ../include/stack.h // 包含接口聲明 #include stdexcept // 用于 std::underflow_error #include vector #include deque // 為了演示多容器支持 #include string namespace mylib { // ------------------------------------------------------------ // 成員函數(shù)定義 // 注意所有函數(shù)都是模板定義必須放在頭文件或此文件中 // ------------------------------------------------------------ // 構(gòu)造函數(shù)定義 (已為默認(rèn)顯式定義亦可) // template typename T, typename Container // StackT, Container::Stack() default; // 帶容器參數(shù)的構(gòu)造函數(shù) template typename T, typename Container StackT, Container::Stack(const Container cont) : c(cont) {} template typename T, typename Container StackT, Container::Stack(Container cont) : c(std::move(cont)) {} // empty 和 size 已在類內(nèi)定義為inline此處無需再定義。 // 但如果定義在類外需要如下 // template typename T, typename Container // bool StackT, Container::empty() const noexcept { return c.empty(); } // top() 成員函數(shù) template typename T, typename Container typename StackT, Container::reference StackT, Container::top() { check_empty(); return c.back(); } template typename T, typename Container typename StackT, Container::const_reference StackT, Container::top() const { check_empty(); return c.back(); } // push() 成員函數(shù) template typename T, typename Container void StackT, Container::push(const value_type value) { c.push_back(value); } template typename T, typename Container void StackT, Container::push(value_type value) { c.push_back(std::move(value)); } // emplace 成員函數(shù) template typename T, typename Container template typename... Args void StackT, Container::emplace(Args... args) { c.emplace_back(std::forwardArgs(args)...); } // pop() 成員函數(shù) template typename T, typename Container void StackT, Container::pop() { check_empty(); c.pop_back(); } // swap 成員函數(shù) template typename T, typename Container void StackT, Container::swap(Stack other) noexcept(noexcept(std::swap(c, other.c))) { using std::swap; swap(c, other.c); } // 私有輔助函數(shù) check_empty template typename T, typename Container void StackT, Container::check_empty() const { if (c.empty()) { throw std::underflow_error(Stack::top/pop: empty stack); } } // ------------------------------------------------------------ // 顯式實(shí)例化部分 // 告訴編譯器請為以下具體類型組合生成代碼 // ------------------------------------------------------------ // 實(shí)例化默認(rèn)容器為 std::vector 的 Stack template class Stackint; template class Stackdouble; template class Stackfloat; template class Stacklong; template class Stackchar; template class Stackstd::string; // 實(shí)例化使用 std::deque 作為底層容器的 Stack template class Stackint, std::dequeint; template class Stackstd::string, std::dequestd::string; // 甚至可以實(shí)例化一個元素類型為自定義類的Stack假設(shè)有一個簡單的Point類 // 注意這要求Point類的定義在實(shí)例化時可見即包含Point.h // #include Point.h // template class StackPoint; } // namespace mylib關(guān)鍵點(diǎn)解析包含接口首先必須包含stack.h這樣編譯器才知道Stack類的聲明。成員函數(shù)定義所有模板成員函數(shù)的定義都寫在這里。注意函數(shù)簽名必須與頭文件中的聲明完全一致包括模板參數(shù)列表、返回類型、限定符const,noexcept。typename關(guān)鍵字在定義中當(dāng)引用依賴模板參數(shù)的嵌套類型如StackT, Container::reference時必須使用typename前綴來告訴編譯器這是一個類型而不是靜態(tài)成員。顯式實(shí)例化語句template class Stackint;這是魔法發(fā)生的地方。這一行代碼指示編譯器請使用int替換模板參數(shù)T使用默認(rèn)的std::vectorint替換Container生成Stackint, std::vectorint這個具體類的所有成員函數(shù)代碼。生成的代碼將被編譯進(jìn)當(dāng)前的stack.cpp翻譯單元并最終進(jìn)入stack.o。支持多種實(shí)例化我們可以為不同的類型和不同的底層容器進(jìn)行實(shí)例化。這展示了模板的靈活性但同時也意味著你需要預(yù)見到所有可能的用法。4.4 客戶端使用apps/main.cpp現(xiàn)在我們來編寫一個測試程序看看如何使用這個分離編譯的棧。// apps/main.cpp #include iostream #include string // 只包含輕量級的接口頭文件 #include ../include/stack.h int main() { std::cout 測試 mylib::Stack std::endl; // 1. 測試默認(rèn)的 int 棧 (底層容器為 std::vector) mylib::Stackint intStack; std::cout intStack 初始是否為空? std::boolalpha intStack.empty() std::endl; intStack.push(42); intStack.push(100); intStack.emplace(77); // 使用 emplace 直接構(gòu)造 std::cout 壓入元素后棧頂是: intStack.top() std::endl; std::cout 棧大小: intStack.size() std::endl; intStack.pop(); std::cout 彈出一次后棧頂是: intStack.top() std::endl; // 2. 測試 std::string 棧 mylib::Stackstd::string strStack; strStack.push(Hello); strStack.push(World); std::cout \nstrStack 棧頂: strStack.top() std::endl; // 3. 測試使用不同底層容器 (std::deque) mylib::Stackdouble, std::dequedouble dequeStack; dequeStack.push(3.14159); std::cout \ndequeStack 棧頂: dequeStack.top() std::endl; // 4. 測試異常安全 mylib::Stackint emptyStack; try { // emptyStack.top(); // 這行會拋出異常 // emptyStack.pop(); // 這行也會拋出異常 std::cout \n嘗試操作空棧... std::endl; int val emptyStack.top(); // 應(yīng)該拋出異常 std::cout 錯誤這行不應(yīng)該被執(zhí)行。 std::endl; } catch (const std::underflow_error e) { std::cout 成功捕獲異常: e.what() std::endl; } // 5. 測試 swap mylib::Stackint stackA; stackA.push(1); mylib::Stackint stackB; stackB.push(2); std::cout \n交換前: stackA.top() stackA.top() , stackB.top() stackB.top() std::endl; mylib::swap(stackA, stackB); // 或 stackA.swap(stackB); std::cout 交換后: stackA.top() stackA.top() , stackB.top() stackB.top() std::endl; std::cout \n 所有測試通過 std::endl; return 0; }4.5 編譯與鏈接這是檢驗(yàn)我們分離是否成功的關(guān)鍵步驟。我們需要分別編譯main.cpp和stack.cpp然后將它們鏈接在一起。使用 GCC/Clang 命令行# 進(jìn)入項目根目錄 your_project/ # 編譯主程序只需要看到 stack.h 聲明 g -stdc11 -I./include -c apps/main.cpp -o build/main.o # 編譯模板實(shí)現(xiàn)和顯式實(shí)例化 g -stdc11 -I./include -c src/stack.cpp -o build/stack.o # 鏈接兩個目標(biāo)文件 g build/main.o build/stack.o -o build/stack_demo # 運(yùn)行程序 ./build/stack_demo使用 CMake (推薦) 創(chuàng)建一個CMakeLists.txt文件在項目根目錄cmake_minimum_required(VERSION 3.10) project(SeparatedStackDemo) set(CMAKE_CXX_STANDARD 11) # 創(chuàng)建庫目標(biāo)編譯 stack.cpp生成靜態(tài)庫 libstack.a add_library(mystack STATIC src/stack.cpp) # 告訴編譯器在 include 目錄中查找頭文件 target_include_directories(mystack PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) # 創(chuàng)建可執(zhí)行文件目標(biāo) add_executable(stack_demo apps/main.cpp) # 將可執(zhí)行文件鏈接到我們的庫 target_link_libraries(stack_demo mystack)然后使用CMake構(gòu)建mkdir build cd build cmake .. make ./stack_demo如果一切順利程序?qū)⒊晒幾g并運(yùn)行輸出測試結(jié)果。這證明我們的顯式實(shí)例化分離策略成功了main.cpp只看到了簡潔的接口而具體的模板代碼只在stack.cpp中被編譯了一次。5. 進(jìn)階技巧與避坑指南在實(shí)際項目中僅僅實(shí)現(xiàn)分離還不夠我們還會遇到一些更復(fù)雜的情況和常見的“坑”。5.1 處理模板友元函數(shù)如果你的模板類有非成員友元函數(shù)比如重載的運(yùn)算符它們的分離會稍微麻煩一些。友元函數(shù)本身不是類的成員但它的聲明又依賴于模板類。錯誤示例鏈接錯誤// stack.h templatetypename T class Stack { // ... friend std::ostream operator(std::ostream os, const StackT stk); }; // stack.cpp templatetypename T std::ostream operator(std::ostream os, const StackT stk) { // 實(shí)現(xiàn) } template std::ostream operator int(std::ostream, const Stackint); // 顯式實(shí)例化問題在于這個友元聲明引入的是一個非模板函數(shù)它是每個StackT的特例的友元。對于Stackint友元是operator(ostream, const Stackint)。但我們在.cpp中定義的是一個函數(shù)模板兩者不匹配。正確做法在頭文件中定義包含模式最簡單將友元函數(shù)實(shí)現(xiàn)直接放在類聲明內(nèi)部或頭文件末尾。聲明一個函數(shù)模板并使其成為友元// stack.h templatetypename T class Stack; // 前向聲明 templatetypename T std::ostream operator(std::ostream os, const StackT stk); // 函數(shù)模板聲明 templatetypename T class Stack { // ... friend std::ostream operator T(std::ostream os, const StackT stk); // 注意這里的 T };然后在stack.cpp中實(shí)現(xiàn)這個函數(shù)模板并對其進(jìn)行顯式實(shí)例化。這種方法較為復(fù)雜。實(shí)操心得對于模板類的簡單友元函數(shù)我強(qiáng)烈建議直接采用包含模式在頭文件里實(shí)現(xiàn)它。這避免了復(fù)雜的語法和潛在的鏈接問題除非這個函數(shù)體非常龐大且嚴(yán)重影響編譯時間。5.2 分離模式下的類型限制這是顯式實(shí)例化方案最大的痛點(diǎn)。如果用戶想使用一個你沒有預(yù)見的類型比如Stackstd::complexdouble鏈接器會報錯。解決方案預(yù)判和提供常用類型在庫的stack.cpp中實(shí)例化所有你認(rèn)為用戶可能用到的常用類型如所有基本數(shù)據(jù)類型、std::string、常用標(biāo)準(zhǔn)容器等。提供“實(shí)例化頭文件”創(chuàng)建一個額外的頭文件比如stack_instantiations.ipp里面包含所有顯式實(shí)例化語句。然后讓用戶選擇如果用戶只用你預(yù)定義的類型他們正常鏈接你的庫即可。如果用戶需要新類型他們可以創(chuàng)建一個自己的.cpp文件包含你的stack.h和stack_instantiations.ipp或者直接復(fù)制里面的語句并添加他們自己的template class StackMyType;然后編譯這個新的.cpp文件并與他們的程序鏈接。妥協(xié)使用包含模式對于需要極致靈活性的通用庫組件最終可能還是得回歸包含模式并通過其他手段如預(yù)編譯頭文件PCH來緩解編譯時間問題。5.3 編譯防火墻與Pimpl慣用法有時即使使用包含模式模板實(shí)現(xiàn)中依賴了大量沉重的頭文件如windows.h,boost/asio.hpp也會污染用戶的編譯環(huán)境拖慢編譯速度。這時可以使用“編譯防火墻”技巧結(jié)合PimplPointer to Implementation思想。思路將模板的實(shí)現(xiàn)細(xì)節(jié)封裝到一個非模板的基類或?qū)崿F(xiàn)類中這個實(shí)現(xiàn)類在單獨(dú)的.cpp里編譯對用戶不可見。模板類本身只持有這個實(shí)現(xiàn)類的指針并轉(zhuǎn)發(fā)調(diào)用。// stack.h (對用戶可見非常輕量) templatetypename T class Stack { public: Stack(); ~Stack(); void push(const T val); T pop(); private: class Impl; // 前向聲明不透明指針 std::unique_ptrImpl pImpl; }; // stack.cpp (用戶不直接編譯) #include “stack.h” #include vector #include heavy_header.h // 沉重的依賴在這里 templatetypename T class StackT::Impl { std::vectorT elems; // ... 所有具體實(shí)現(xiàn) }; templatetypename T StackT::Stack() : pImpl(std::make_uniqueImpl()) {} // ... 其他轉(zhuǎn)發(fā)函數(shù)的定義這種方法將模板的復(fù)雜性轉(zhuǎn)移到了.cpp文件中但代價是引入了動態(tài)分配的開銷和額外的間接層。它更適用于接口穩(wěn)定但實(shí)現(xiàn)復(fù)雜且依賴多的場景對于簡單的棧來說有點(diǎn)殺雞用牛刀。5.4 常見編譯與鏈接錯誤排查undefined reference to Stackint::function()原因這是最典型的錯誤。意味著鏈接器找不到Stackint成員函數(shù)的定義。排查如果使用顯式實(shí)例化檢查stack.cpp中是否有template class Stackint;語句。檢查你是否將stack.cpp加入了編譯鏈接過程。如果使用包含模式檢查stack.hpp中的函數(shù)定義語法是否正確是否遺漏了template typename T前綴或者函數(shù)簽名是否與聲明嚴(yán)格一致。注意即使你在stack.cpp里寫了實(shí)現(xiàn)但沒有進(jìn)行顯式實(shí)例化編譯器也不會為任何類型生成代碼鏈接時必然失敗。multiple definition of Stackint::function()原因在包含模式下如果你不小心在多個.cpp文件中都包含了stack.hpp的實(shí)現(xiàn)部分并且這些函數(shù)定義沒有被隱式或顯式地聲明為inline那么在鏈接時就會產(chǎn)生重復(fù)定義錯誤。解決在頭文件中定義模板函數(shù)時它們默認(rèn)就是inline的因?yàn)槊總€實(shí)例化都是獨(dú)立的。但如果你在類外定義確保它們都在頭文件里。如果采用.ipp包含方式確保該.ipp文件只被一個源文件包含通過宏控制或者確保所有定義都在頭文件內(nèi)。error: specialization after instantiation原因在同一個翻譯單元中你先隱式或顯式地實(shí)例化了一個模板然后又試圖對它進(jìn)行特化。編譯器會困惑。解決調(diào)整代碼順序確保所有特化都出現(xiàn)在任何可能的實(shí)例化之前。通常將特化代碼放在頭文件末尾、任何使用該模板的代碼之前。6. 總結(jié)與最佳實(shí)踐建議經(jīng)過這一番從原理到實(shí)戰(zhàn)的深入探索你應(yīng)該對C模板類的定義與實(shí)現(xiàn)分離有了透徹的理解。最后分享一些我總結(jié)的最佳實(shí)踐幫助你在實(shí)際項目中做出合適的選擇優(yōu)先考慮包含模式對于大多數(shù)項目尤其是模板代碼量不大、或者處于快速迭代階段時直接使用包含模式把所有代碼放在.hpp或.h文件中是最簡單、最不容易出錯的選擇?,F(xiàn)代編譯器的增量編譯和預(yù)編譯頭文件PCH技術(shù)可以很大程度上緩解編譯時間問題。謹(jǐn)慎使用顯式實(shí)例化僅在以下情況使用你正在編寫一個庫并且明確知道用戶只會使用有限的幾種類型如數(shù)值類型、字符串。編譯時間確實(shí)是項目的瓶頸并且模板實(shí)現(xiàn)非常復(fù)雜。你愿意承擔(dān)維護(hù)顯式實(shí)例化列表的額外開銷。良好的文件命名習(xí)慣.h/.hpp用于包含模式或僅包含聲明的頭文件。.ipp/.impl/_inl.h常用于存放需要被包含的模板實(shí)現(xiàn)代碼以區(qū)別于普通頭文件。.cpp用于顯式實(shí)例化或非模板代碼。利用現(xiàn)代構(gòu)建工具預(yù)編譯頭文件PCH將穩(wěn)定的、常用的模板頭文件放入預(yù)編譯頭可以大幅提升編譯速度。模塊C20這是未來的終極解決方案。C模塊允許你真正地分離模板的接口和實(shí)現(xiàn)并且編譯一次后實(shí)現(xiàn)部分可以被高效地復(fù)用。如果你的項目可以使用C20或更高標(biāo)準(zhǔn)強(qiáng)烈建議開始探索模塊。測試驅(qū)動開發(fā)無論采用哪種分離方式都要為你的模板類編寫全面的單元測試。測試應(yīng)覆蓋所有你顯式實(shí)例化的類型以及邊界情況如空棧操作。這能確保你的分離沒有引入錯誤。回到我們最初的棧模板選擇哪種方案最終取決于你的具體需求是追求極致的編譯速度與代碼隱藏還是追求極致的靈活性與簡單性。理解每種方案背后的原理和代價你就能在未來的C項目中游刃有余地做出最適合的架構(gòu)決策。記住沒有銀彈只有權(quán)衡。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
欧洲综合无码| 不卡九肏| 热久久国产精品视频大陆精品| 九一性生活免费视频| 97碰| 伊人色综合超碰| 2017天天拍大香蕉| 久久9 9 9精品| aV中文麻| 精久久久91| 亚洲无码国产精品久久| av情色影音| 91精品老女人| 久久久啊啊| 98超碰欧美| 国产伦精品一区二区三区在线观| 亚洲在线网站| 91 国产丝袜在线放观看| 亚洲色图欧美激情| 日本不卡三级网在线播放| 91老司机在线| 亚洲色图超碰在线| 五月天婷婷在线看| 目产99999久久999| 小少妇| 东京热毛片177b2viP| 五月天婷婷欧美三区| 欧美一级二级三级| 97在线免费看| 国产精品极品美女视频| 中文熟女五十乱码在线| 久久婷婷六月综合| 黄片qw| 日日干夜夜欢| 99色综合| 日韩三级在线观看网站| 97超碰影音| 国产综合操逼高清| 女性91网站| 强奸少妇AV导航网| 天天精品| 国产日韩久久| 自拍欧美| 亚洲色综合| 欧亚无码视频| 国产精品一区二区密臀| 欧亚第一综合网| 1禁看欧美黄片免费看| 成人a级高清视频在线观看| 婷婷另类小说| 六月丁香五月婷婷| 精品久久久久av影院| 国产精品动态一区二区三区四四| 少妇500双飞99| 福利伊人玖玖国产| 丁香九月婷婷| 久久熟女久| 久9热| 国产一区自拍欧美日韩| 玖玖久久久| 亚洲熟女乱色| 婷婷色婷婷| 最近2018中文字幕在线高清第一页| 国产成人精品一区| 老司机免费视频在线91| 91女神在线视频| 乱伦a片视频| 亚洲资源吧| oumeisetupian| 综合欧美日韩在线观看| 久久永久无码人妻视频| 国产熟女一区二区| 抽插亚洲无码| 极品一区二区三区免费| 狠插 制服 自拍| 国产高清无码一区二区三区四区皇冠| 乱伦熟女论坛| 精品对白久久不卡| J?P?NESEHD熟女熟妇伦| 欧美日韩久久精品爱爱| 亚洲图片欧美另类综合免费视频大大香| 偷拍欧美综合| 97色冈| 亚洲国产成人高清在线| 日韩av不卡在线看| 亚欧无码线免费观看视频| 久久精品操| 日韩精品9区| 91扒丝袜综合在线| 精品一区二区麻豆| 亚洲人在线成线成人| 婷婷五月天av| www.色99| 青娱乐av在线| 熟女丰满人妻一区| 亚洲精品色| 天美麻花大全视频| 亚洲 欧美都市激情| 色综合婷婷| 国内精品不卡无毒99999| 做爱A级亚欧| 蜜乳AV.COM| 国模私拍一区二区三区神乳| 青娱乐国产剧情av一区| 精品无码久久久久久久久果冻糖心| 欧美劲爆第一页| 欧美激情内射| 精品97久久| 亚洲风情在线观看| 欧美影院一区二区三区| 国内亚洲高清无码| 国产无码三级视频在线观看| 一本色道无码DVD中文字幕| 欧美资源| 一级AV性爱| 秋霞一级A片黄色视频| 亚洲欧美高清无码| 啪啪啪精品| 99久久精品无码一区二区毛片免费| 最新日日夜夜天天干干| 久99久视频| 亚洲国产日韩欧美熟妇在线| 一区二区你上我| 五月丁香亭亭| 色月天AV导航| 超碰1997| 亚洲第一页色网| 国产搭汕a级片| 91精品网站| 屁股久久久久久久久久| 一级做a爰片性色毛片久久| 伊人专区一区二区三区| 一区二区三区机械有限公司| 人人乐大香蕉| 麻豆人妻少妇在线免费观看| 国产熟女精品区| 超碰久草| 2021国产成人精品久久| 亚洲乱色熟女一区| 美女国产一区二区久久| 激情丁香五月| 乱老熟女一区二区三区| 亚洲人妻久久久| 男人的天堂com| 女性91网站| 国产精品 久久久精品一牛| 黄色免费网页无码| 无码免费一区二区三区啪啪| 亚洲青色欧美| 亚洲男人天堂手机版| www.99色| AV高清一区| 欧美成人A√在线一区二区| 成人无码在线视频网站| 91操人| 色婷婷综合久久久久中文一区二区| 天天操人人操骚逼网站| 国产熟女精品一区二区| 强奸乱伦Av网| 久久手机视直播| 日韩丨制服丨中文|在线| 99re视频在线播放青草| 女人被男人桶爽视频网站| 亚洲精品美女久久久久久久久| 情色日播放AV| 国产91美女视频| 亚洲伊人a线观看视频| 色综合色综合网| 久久亚洲人妻| 丰满人妻一区二区三区色-百度| 蜜乳AV一区| 中文字暮97| 大香交| 久久精品国产亚洲AV清纯| 亚洲av淫乱| 91亚州欧美| 亚洲 欧美综合| 国产一区二区啪啪视频| 日韩一级二级三级免费看完整版国语版| 久久αⅴ| 国产成人网站在线观看| 色综合20p| 男人女人18禁片免费看网站| 青青国产精品在线| 中文字幕青青草| 欧美一级特黄淫片在线观看| 精品无码一二三四区| 午夜爽爽爽| 91在线无码精品秘 软件| 97香蕉人人乳| 日本潮催一卡操| caorenqi shipin| 亚州五月| 性吧在线视频| 日本熟妇人妻一区二区三区| 麻豆这里只有精品| 精品人妻一区二区三区蜜桃视频| 国产吞精a级片激情电影| 性交一区二区在线播放| 欧美一区二区三区蜜桃| 九九av| 亚洲欧洲精品视频发布| 婷婷五月激情综合| 伊人国产AV| 91精品无码人妻系列| 91久久国外网| 天天做日日做天天欢。| 大香交| 国产AV高清AV无码| 九九九九亚洲| 成人开心网在线视频| 强奸乱伦Av网| 96精品久久久| 97欧美精品综合| 操逼无码操逼| 欧美亚洲日本视频久久久 | 天天综合亚洲综合| 天美国产精品| 白丝被操91| 国产精品丝袜久久亚洲不卡| 久久精品国产免费观看99| 日本 情色 1区2区3区| 亚洲一区二区三区欧美日韩| 999精品久久久久久久| 亚州情色j区| 高清国产精品福利网站| 啊好爽快点-国产一区二区三区撒尿在线-成人AV| 亚洲激情综合另类男同| 久久激情视频| 欧美 日韩 另类 亚洲| 91久久精品中文字幕| 色呦色呦色精品| 九九性爱网| 九九九网站| 97视频观看| 精品亚洲国产成人精品| 欧美色性情| 欧美综合色站| 麻豆天美国美国产| 色呦呦呦在线观看视频| 凌辱美少妇久久aV| 欧美久久婷婷| 综合网色| 九九热久久99精品re| 亚洲好色人妻| 蜜奶av| 中文字幕性感少妇av| 淫荡网址| 精品97久久| 欧美天堂超碰97| 超碰人人在线| 久久久久亚洲AV无码专区少妇| 国产高清在线自在拍69| 欧美专利1区2区3区4区5区免费| 亚洲图片日本AⅤ欧美在线| 亚洲中文字幕一区| 色诱avtt| 国产日本熟女顶级一区二区三区视频| 操高情无码| 日少妇视频| 91精品国产乱码| 神马久久久久眼| 亚洲超碰AV| 精品人妻一区二区三区四区石在线| 天天综合站| 精品视频97| 丁香五月婷婷基地| 欧亚乱色熟女一区二区| 天天日天天插| 日韩AV无码中文一区二区| 色牛aV| 97ai亚洲| 东方亚洲在线操逼天堂| 久久久久久中文版| 欧美亚洲激情小说| 亚洲一区中文字幕久久,果冻传媒一区二区天美传媒 | 女性91网站| 超碰综合97在线| 夜夜国产一区| 另类av天堂| 欧美不卡在线美女| 欧美亚州手机在线| 任你草| 蜜桃无码AV一区二区| 亚洲一级性爱视频免费看| 亚洲影院成人| 久久久九九九| 国产亚洲性生活视频播放| 久久精品久| 久久97视频| 91视频女生| 国产精品久久久久999| 麻豆传媒一区二区在线观看| 欧洲精品区| 午夜福利在线视频1000| 欧美天天综| 精品人妻一区二区三区-国产| 综合婷婷| 亚洲欧美大| 啊灬啊灬啊灬好深灬快高潮了动漫-国产字幕国产在线观看-B049AV | 国产精品国产拍高清AV| 人妻精品一区二区在线| 91人妻素女| 亚洲图片欧洲图片aⅴ| 国产传媒操逼视频| 日韩成人精品视频自拍| 国产精品久久久久av| 人人操人人uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii | 日韩欧美性吧婷婷乱伦大香蕉| 舔足天天操天天射| 精品一级毛片在线观看| 91被操| 成人无码在线超碰网| 久久久亚洲Av| 欧美视频一区二区在线| 欧美疯狂做爰xxxx| 熟女精品一区二区三区| 国产乱弄免费在线视频。 | 九色97| 欧美老熟另类| 亚州欧美总和| 国产91美女视频| 99re9| AV乱伦专区| 国产精品无码av在线| 国产精品一级片在线看| 成人精品电影| 亚洲男人天堂2013| 99在线观看视频在线高清| 久久久不卡| 日韩在线欧美精品一区二区| 天天操天天舔| 97天天爽| 97视频新免费| 亚洲久久久久| 中日韩久久久| 色哟哟国产精品免费网址| 欧美性爱网97| 天堂亚洲欧美| 亚洲欧美精品国产一区二区| 中亚精品极乱| 亚洲AV无码久久精品蜜桃小说| www男人天堂| 亚洲精品国产精品乱码不卡| 啊啊啊啊啊舒服| 天天网综合| 一区操逼| 婷婷五月天在线观看| 久久国产视频专区一二三| 熟女高潮合集-永久久久-成人AV| 久久久久久久久9| 大香蕉伊人网| 欧美性爱在线无码| 色天堂综合| 一二三区精品视频| 黑人精品成人一区二区三区| 暖暖精品二区三区观看| 竹菊一区二区三区AV线| 日韩黄片视频试看| 无码免费一区二区三区啪啪| 久久久久久中文| 中文字幕人妻资源在线| 婬女免费一二三区A片| av大香蕉网站| 91精品国产91综合久久蜜臀| 人妻少妇久久久| 久久原创中文| 日韩欧美成人性爱在线| 青青草视频在线观看一区二区| 激情文学亚洲| 久久免费精品视频免一| 欧美色日本| 九九九精品| 男人的天堂啪啪啪啪啪蜜桃不卡| 超碰社区97| 深夜国产一区二区三区在线看| 日本一二三高清| 中文久久久| 91丨九色丨国产打屁股| 风月影院男女十八禁| 国产高清视频无码在线| 青青11操操操操操操操操| 91美女视频直播| 大香网站| 久久久精品,3| 精品国产肉丝袜在线拍国语| 国产诱惑| 秋霞曰韩R级| 中文字幕一区二区三区蜜桃视频| 巨爆乳一区二区爆乳区| 中文字幕少妇色| 国产深喉视频一区二区| AV 少妇 人妻 偷拍| 麻豆一区二区三区在线看| 伊人影院综合是一个与深夜成人在线 | 91成人亚洲色图| 中日韩熟女| 精品中文日韩字幕视频| 国产成人无码啪| 操逼999| 精品国产丝袜一区二区三区乱码| 精品9区| 欧美aaaaaaa| 欧美91丝袜| 在线看片国产精品每日更新| 97人妻人人躁人人玩人人| 欧亚在线视频| 九九九不卡| 操人妻少妇中文| 在线97视频| 第二页中文字幕| 成年人黄色视频免费| 91麻豆天美传媒HD| 最新中文字幕精品在线| 青草伊人网| 亚欧精品久久久久久久久久久| 久久人妻熟女一区二区| AV色天香在线| 国产日韩欧美亚洲精品95 | 久久人妻四季| 曰本人妻人人澡人人夹| www.人人摸在线视频| 婷婷五月花| 一级毛片电影免费看| 久久久性爱视频| 久久久久亚洲Aⅴ无码| 国产搭汕a级片| 久久9精品视频| 国产成人综合在线播放| 国产麻豆91欧美一区二区久久婷婷国产精品| 色丁香久久| 天堂v无码免费视频| 欧洲小说色图视频另类| 欧美成人9797| 顶级丝袜熟女一区二区三区 | 天天舔天天日天天射| 欧美精品自慰系列寂寞少妇| 九九草| 成人熟女区| 99在线免费视频| 成人AV超碰免费在线| 久久久九| 嗯嗯啊好大| 色婷婷综合网| 欧美一区二区观看在线| 人人么人人操| 人妻精品一区二区| 国产精品久久久久久久久久久久久久久久 | 东京热男人天堂| 亚洲综合情色| 91性生活久久久| 亚洲婷婷五月天| 精品国产丝袜一区二区三区乱码| 在线a亚洲视频播放在线| 精品人妻伦一区二区三区久久| 97超碰国产亚洲精品资源| 国产精品久久久久久片| 高清无码久操视频| 亚洲天天操| 色97国产69香蕉| 超碰天天操| 中文字幕av色| 天天操夜夜操| 婷婷九月| 九九在线视频| 激情综合五月| www九九热| 久操凹凸视频| 很黄很色的视频在线观看| 日日爱99| 久9无限国产| 新91视频.cmp| 日韩BBN| 人妻五十路在线| 亚洲av热热色| 青青草视频久久久久| 日本欧美韩国日产片片在线看免| www.av在线观看| 久久久久成人亚洲国产| 日韩亚洲国产视频| 无码精品人妻一区二区三区妖精| 欧美日韩不卡a片| 亚洲A曰本VA欧美VA视频| 啪啪综合网| 啊啊啊网站| 啪啪自拍九九综合| 日夜伊人网| 亚洲国产成人精品女人久久久| 少妇的嫩逼图片| 亚洲中文字幕av| 色噜噜人妻av中文字幕| 亚洲成人在线资源| 日韩大香蕉AV影片| 97综合国产| 最近二区三区视频大全| 日本一级特级毛片视频| 超碰97欧美| 亚洲欧美第一页| 中文字幕国产在线天堂| 中国一级操逼视频| 日本国产欧美高清在线| 综合色图区| 色婷婷亚洲婷婷| 国产精品一区二区三区在线密挑| AV天堂丝袜| 中文字幕加勒比海高清无码免费视频| 欧美第二页| 97天天日| 国产福利电影| 蜜乳AV网址| 热九九精品| 日韩成人色图| 欧美午夜视频| 欧亚 另类 久| 国产精品不卡av免费在线观看| 九九视频黄色片| 玖玖资源综合在线视频| 男人的天堂不卡一区二区| 日韩精品三区四区| 97视频在线视频| 久久久久99精品成人片蜜臀| 插入逼91| 亚洲最大网站av| 日本 欧美 亚中文字幕| 亚洲蜜臀懂色| 99精品综合久久久久五月天| 国产一区二区三区高清视频| 国产一级操B视频| 欧美激情五月天| 美女诱惑在线一区| 91天堂| 国产51色综合久久免费| 狠狠狠狠狠狠| 色九九九综合| 欧美黄页| 日本女人操逼| 欧美性爱一区二区三区四区 | 亚洲日韩AV视色| 亚洲熟久久| 亚洲图片欧美色图| 色爱三区| 日韩人妻无码精品系列| 91精品91久久久中77777| 天天色天天干天天爱| www.丁香五月| 秋霞鲁丝午夜无码一区二区三| 葡萄牙性视频一二区 | 不卡在线观看视频| hd成人一区二区在线| 丝袜内射| 精品78| 91麻豆va国产精品| 亚洲国内精品成人不卡| 黄色视频高清无码网站| 精品久热| 涩亚洲欧洲| 日韩精品一区二区高清| 亚洲,欧美,春色,另类| 青青草国产一区二区三区| av网站国产主播在线| 97人人干| 蜜臀99久久精品久久久久久| 国产精品呦一区二区三区| 色综合潮| 亚洲综合在线视频| 精品中文一区二区| 久久精品国产亚洲AV高清演员表| 91色鬼| 亚洲精品久久久久久久蜜桃臀| 丰满人妻大屁一区二区| 视频在线中文字幕| 新婚人妻扶着粗大强行坐下| 我中文字幕6区| 国产三级资源在线观看| 裸体女人草逼视频播放一区,二区,三区,四区,五区 | 欧中美三级一区二区三区| 操逼片中文| 亚洲视频二区 | 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区 | 婷婷丁香五月天亚洲天堂网| 精品人妻一区二区三区夜夜| se吧提供国产乱老熟视频胖女人| 麻豆国产原创AV色哟哟| 乱伦日本中文自拍| 国产污视频麻豆传媒一区二区| 欧美激情一区| 日本三级小说中文字幕| 人人性爱视频免费| 九九热视频这里只有精品| 日本精品中文字幕视频| 熟妇艹鸡八| heyZO天然素人无码AⅤ专区| 欧美亚洲AN| 国产成人欧美一区二区三区的国产| 人妻无码久久一区二区三区免费| 亚洲性爱免费电影| 中文一区在线日| 国产精品自拍欧美在线| 伊人性在线视频| 色优久久| 精品日韩人妻精品一二三区| 91高跟美女在线播放| 韩国黄片aaaa| 久久久精品,3| 99999无码| 国产操逼视频在线观看| 欧美玖玖爱免费玖玖| 久久性爱大全| 91熟女视频| 黄呦呦在线| 女人午夜视频777| 校园春色 亚洲| 大香蕉伊人网WWWn0n| 亚洲欧美在线观看无码| 天天综合网合集91| 9 9精品一区二区三区| 老司机福利青青草| 91美女国产在线| 婷婷在线视频| 亚洲av综合色区图片亚洲| 99色综合| 欧美91丝袜| 日本狠狠干| 欧美激情性久久久久久| 情色图区| 中文字幕人妻色偷偷久久皮| 岛国精品视频在线观看| aaa亚无码专区| 天天草AV| 97综合在线观看| 老司机老司机午夜影院| 中文字幕熟女人妻丝袜| 国产地址二三| 性欧美另类高清| 中文字幕一区二区韩| 中国特猛少妇色xxx| 日本东京热大香蕉a片| 久久久久久久人妻| 操逼www.| av三级电影在线播放| 国产少妇内射| 啊好爽快点-国产一区二区三区撒尿在线-成人AV | 欧美丝袜美女电影一二三四区| 99热久| 国产欧美一级在线观看| 中文字幕精品探花视频| 亚洲欧美综合网| 日日干男人的天堂| 91在线免费观看处女| 久久亚洲婷婷| 强奸乱伦中文字幕AV| 久久精品一区二区一8| 久久九九精品一区二区| 久噜噜| 超碰97网址| 人妻激情另类| 五月天婷婷色| 亚洲欧洲国产综合av| 亚洲小电影免费涩涩成人在线高清| 麻豆成人影音在线| 亚洲熟女乱综合一区二区在线-...亚洲国产日韩欧美一区二区三区,久久久久久精 | 欧美另类色图片| 中文字幕精品区先锋资源| 亚洲密乳AV| 91av熟女人妻| 天天看天天日天天操| 久久9精品| 男人的天堂kva| 超碰97久久国| 欧美亚洲国产日本在线,久久精品国产| 久久久不能久久久久| 东京热激情视频一二三区| 婷婷五月综合在线| 色丁香五月婷婷| 国产精品青草综合久久| 成人福利视频网| 黑人操一区二区| 美中日韩无码| 无码乱人伦中文视频| 3028国产精品| 成人性爱视频在线看| 奇米四色影视777久久久| 亚洲囯产精品女人久久久| 久久久精品91八戒| 中文精品一区二去| 精品人妻一区| 熟女六十路| 久久综合激情| 亚洲色图大香| 九久9热| 91伊人影视综合| 人妻社区男人天堂| 久久久久国产| 熟妇高潮二区三区| 97久久超碰日韩精品| 少妇三p| 婷婷婷婷婷婷久久久久| 波多野42部激情无码喷潮| 豆花视频操逼网址| 插穴性爱视频在线观看| 日韩少妇一区二区三区| 久久久网站| av中文字幕在线熟女| 九九久久一区二区三区| 欧美在线l亚洲| 久久久久久久久国产| 精品日韩产品在线,日韩在线不卡视频,欧美日韩免费专区/久, | 97在线免费看| 97超碰资源网| 久久久青草青青国产亚洲免观精品高清完整版_97久久综合区小说区图片区,国精品 | 久久一二三四五六七八九区区| 无码黑人精品一区二区三区三| 亚洲1区2区三区高清中文字幕| 日韩性爱再线视频| 中文字幕精品一区二区精品| 熟女一区二区| 天堂综合| 男人天堂电影院| 欧美精品一区二区少妇免费A片| 国产亚洲日韩在线三区黑人| 久久综合九九| 中文字幕人妻色偷偷久久皮| 噜噜瑟| 亚洲国产美女久久久久| 美國A片| 亚洲情色五月天 | 久久久久久亚洲精品不卡人乳| 一本正道久久熟女| 精品一区99999| 蜜臀中文字幕| 福利在线观看一区二区| 神马精品视频| 欧美性Fer办公室秘书| 麻豆天美91| 懂色AV蜜臀无码精品APP| 欧美 亚洲 制服 精品| 精品妇操一区二区三区| 秋霞Av理论一级在线| 久久久久成人亚洲国产| 99re3这里只有精品| 日韩无码服务区| 狠狠色伊人亚洲综合网站色| 99久久网站| 99蜜桃臀亚洲成人在线观看| 亚洲天堂男| 97人人操人人摸人人爱| 91人妻丝袜无码| 99少妇| 精品视频免费在线一区| 亚洲国产精品久久久久婷婷青年| 亚洲影视第一页| 国产亚洲精品A在线观看下载| 狠狠色婷婷7777久| 屁股久久久久久久久| 狠狠久久手机视频精品| 99热在线播放| 免费男人的天堂| 操操操日本的逼| 欧美亚洲影视| 久久AV无码AV| 狠狠狠狠狠干| 欧美色图自拍| 国产精品一级特黄aaa大片在线观看| 久久国产精品91| 亚洲欧美综合网| 欧美亚洲中文字幕| 亭亭在线资源| 爽极品影院| 美女的肌被草喷水视频| 思思久热在线精品66| 99热色精品| 99热在线只有精品| 中日高清无码操逼视频| 亚洲欧美91√| 久久精视频美日韩在线视频| 色色色色色色色色综合| 国产日韩区| 天美精品一区二区三区四区在线观看 | 97视频在线免费看| 国产熟女精品一区二区| 91爱综合| 国产精品com| 国产原创精品| 成年人黄色视频免费| 97亚洲一区| 18禁看网站一区| 人妻丝袜二区| julia高潮后不停追击中出| 国产精品丝袜在线| 丝袜美腿诱惑亚洲欧美视频在线观看| 人妻熟女一区二区三区视频| www.99色| 欧美性暴力| 成年男人的天堂| 日韩性爱小视频| 91高跟美女在线播放| 91丨豆花丨熟女| 亚洲欧美国产va在线| 国产精品蜜乳AV| 亚洲欧美内射| 猛交交| 亚洲熟女乱色一区二区三区| 免费久久9999| 日韩黄色一区二区三区| 色欲天香天天综合网-成年人三级片网站-欧美乱妇狂野-日韩国产专区-久久久久久 | 亚洲免费成人在线高清无码视频| 欧美 日韩 婷婷 五月| 国精精品无码一二三区水多多| 日本中文字幕熟妇| 综合色久| 日韩成人性日韩成人性爱视频在线免费观看| 快点操死我| 国产精品黄色三级av| 夜夜嗨TV| 天堂日本亚洲欧美| 亚洲 自拍偷拍 欧美| 天天操熟妇| 操人妻少妇中文 | 超碰97丝袜| 国厂麻豆77q4| 女人爽到高潮潮喷18禁网站| 99人妻| 激情五月天校园春色网| 操91| 影音先锋新男人| 97欧美色| 色狠狠综合噜一二三区| 永久免费发布性爱网| 成人小电影网站tex| 91殴美大片| 久久久成人国产精品无码| 淫荡网址| 亚洲AV在线资源| 亚洲欧美校园另类春色| 岛国大片在线观看网站入口| 偷拍盗拍亚洲色图图片| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 国产suv精品一区二区四| 亚洲中文国际强奸字幕| 精品视频在线观看| 久艹99| 91肏屄网| **一级毛片国产| 免费观看网黄| 粉嫩av一区二区三区天美传媒| 啊啊啊啊二区好大| 色色色综合网| aaaa少妇高潮大片| 无码免费在线观看黄色片| 精品人妻一区二区免费看| 抽插爽| 精品一区二区3区| 亚洲精品乱码久久久久久蜜桃麻豆 | 久久最新视频免费观看| 日本天天操| 亚洲一卡2卡3卡4卡乱码网站| 中文一区二区三区影院| 校园春色美腿丝袜| 亚洲欧美日韩电影网站一区 | 九九热九九热| www.婷婷| 人人摸人人叼| 久久精品中文字幕观看| 粉嫩av在线| 人妻天堂网| 后入合集| 91久久精品美女高潮喷水| 久操九九九九九九九九九九九九九九九九九九九九九九九九九九九九 | 蜜汁欧美| 夜夜做夜夜爽精品视频| 美女黑人91神马| 久艹伊人精品综合在线| 久久久久成人蜜桃精品| 色婷婷九月| 国产激情在线| 亚洲av淫乱| 啪一啪免费视频| 亚洲小电影免费涩涩成人在线高清 | 嗯嗯啊啊的视频| 久久久久网站-538在线视频-欧美永久乱码 | 精品久久大胆人体| 人妻精品视频一区二区| 国产精品干干干| se吧提供国产乱老熟视频胖女人| 999综合网| 人妻欧美| 男人的天堂久久久| 啊啊啊好舒服视频| 日韩99999| 女人香蕉久久毛毛片精品| 久久一二三四五六七八九区| 九九av| 黄色十八禁| 91n免费处女| 午夜精品久久久久久久| 久久久久国产精品人妻aⅴ天堂| 日本九九久久99| 欧美日韩美女精品久草一区二区三区| 亚洲人久久久网| 久久久成人精品| 欧美最大综合网| 97欧美色| 国产丝袜啪啪| 久久久新亚洲AV| 日韩欧美大片免费高清啪啪| 少妇熟女1区2区3区| 中字幕人妻一区二区三区| 眼镜人妻101.com| 九月丁香婷婷色| 欧美另类综合久久| 国产女生在线| 女优视频第10页| 神马久久久久眼| 午夜福利区| av草草在线电影| 久久久久久久9999| 久久久久9999| 亚洲精品国产熟女| 69精品久久久久中文字幕| 九九色逼| 日本淫色网| 欧美少妇高潮久久91| q2午夜理论片夜色av| 日韩一卡二卡三卡| 加勒比在线视频一区二区三区| 欧美偷拍| 国产视频一区二区三区在线免费观看| yellow网站免费观看日韩高清无码| 人、人、摸,人、人、草| 大奶啊啊好爽| 中出789在线视频| 亚洲蜜臀精品视频久久| 大学生美女口爆| 亚洲伊人a线观看视频| 静品嫩模一区二区| 一道本东京热加勒比一区二区三区| 色大香蕉97N| 夜夜夜夜久久久久| Sekablack无码一区| 欧美视频中文字幕区| 99久久这里只有精品| 精品一区二区三区蜜桃臀www| 97日亚洲欧美| 国产高清26uuu| 夜夜一区二区| 91女优在线观看| 蜜臀久久99精品久久久久久无删减| 亚洲,日韩,欧美,成人播放| 色婷视频| 亚洲国内精品成人不卡| 大奶的诱惑| 国产精品一二三在线看| 91九久| 久射吧| 欧美一二三级精品在线| 中文字幕在线日亚州9| 国产不卡中文字幕免费avi| 日韩有码中文字幕女同性恋| 韩日性爱av| 久久9精品视频| 青青草原伊人网| 亚洲国产精品9999在线观看| 婷婷在线播放| 亚洲骚男同com| 岛国色情视频在线观看| 超碰亚洲97| 欧日韩一二三f区| 国产亚洲日韩在线三区黑人| 91美女视屏| 无马一区二区| 国产亚州精品美女久久久免费| 欧美激情片一区二区| 国产传媒日韩| 91啪啪视频| 韩国毛片一区二区三区| 一级岛国大片| 亚洲AV免费在线观看| 男人综合网| 欧美黄色大香蕉一区二区| 青青欧洲黑| 国产在线观看91精品一区| 爱射综合| 日本久久超碰| 99久视频| 欧美色亚洲色| 色官网在线| 蜜臀无码一区二区| 芊芊操逼视频无码| 欧美色图下一页| 国产无吗在线播放| 大香蕉伊人一区在线观看| 日韩色| av天天在线观看| 亚洲欧美日韩不卡人妻| 99热9| 校园激情狠狠四射| 91超级碰| 97神马久久| 能看的AV| 三级色影综合网| 中文字幕在线观看丝袜| 春色综合网| 亚洲宅男天堂| 女人久久久| 玖玖视频在线资源一区二区三区| 97色综合中文网| 丁香六月婷婷| 精品对白久久不卡| 欧美久久九九| 国产一级高清免费观看| 天天肏美女| 欧美一区二区三区不卡高清视频| 久无码| 超碰精品日韩欧美国产| 日韩激情视频| 国产人伦a片信息免费片| 欧洲大香蕉| 日韩在线观看中文字幕视频| 97视频播放| 骚货人妻偷情自拍在线视频| 亚洲天堂精品日韩电影| 午夜成人福利影视| 2020中文在线一区二区三区| 激情视频一二三| 国产福利精品最新在线| 亚洲成人ab| 99爱久久视频频| 偷拍亚洲熟女视频播放| 97久久天天综合色天天综合色电影 | 日韩影片中文字幕一区二区三区| 亚洲天堂五月天国产| 欧美影音在线| 色9999日韩国产| 超碰91在线| 另类av综合久久| 天天干人妇| 国产美女高潮| 欧美熟妇亚洲版| 日本女人操逼| 亚洲国产精品无码AV久久| 97自拍一区| 91久久久久久久久18| 永久免费观看的毛片的网站| 啊啊啊啊啊啊啊啊啊啊在线观看| 欧美视频边做饭边橾| 亚洲九九九九| 人妻少妇精品久久久| 丁香五月性| 强奸乱伦AV网址| 欧美少妇高潮| 激情文学 国产一二三aV| 国产精品蜜乳AV| 97干在线| 亚洲电影91| 天综合网| 日韩在线观看字幕精品| 激情综合网亚洲| 亚洲s色图| 手机av天堂久久久久| 亚洲中文日韩欧美大香蕉视频| 在线中文字幕视频| 国产乱子伦一区二区三区免看| 夜夜爽爽爽| 亚洲日韩美国人妻| 久久老女人| 精品国产综合久久福利,热99这里有精品综合久久,99热这里只有免费国产精品,精 | 狠狠色五月亚洲91| 白丝少妇一区二区| 淫妻综合网| 久久精品国产亚洲AV片多多 | 精品少妇高潮久久| 亚洲自拍欧美国产首页网曝| 日日干夜夜干| 亚洲黄色a级片| 国产无码精品高清| 97资源久久| 国产人人干| 九九九九九九成人| 殴美,日韩国产伦精品| 黄aaaaaaaaaaaaaaaaaa色网站| 日韩一区二区精彩视频| 青娱乐av在线| 日语五十路和六十路亚洲国产精品| 亚洲欧美一区二区不卡视频播放 | 可以免费看黄片的视频| 在线播放欧洲免费av| 日韩综合色图| 久热精品在线| 色五月69夫妻| 99re视频在线观看这里只有精品| 亚洲成人一区二区精品| 性videos欧美熟妇hdx| 国产精品在线免费| chaopen97久久| 97超碰免费生活| 最新av在线| 91最新综合| 九九九九九九亚洲| 另类图片五月| 一块操欧美| 国产精品蜜乳AV| 欧美日韩日产免费网站看| 麻豆国产精品午夜视频| 无人区高清电影免费观看一区二区三 www.qmcai2.com | 草草影院最新网址| 国产在线视频午夜精华在| 亚洲激情综合另类| 女优大全 - 91n| 色97欧美| 婷婷性网| 亚州性9| 国产老女人久久毛| 熟妇一区二区| 日躁天天爽爽| 久久久久国产精品久久久| 精品69网| 欧美亚洲首页| 色综91| 测评在线观看AV| 亚洲日韩av专区无码| 曰韩人妻中文字幕在线| 操逼网站网站| 一区二区精品日韩欧美在线观看| 校园春色欧美| 日韩中文字幕精品一二三事国产精品| 经典丝袜一区| 玖玖爱伊人玖玖爱| 999熟女精品| 人伦四五区| 欧美天天干| 色激情综合网站| 九九九久久久| 日本1区2区不卡视频| se01国产在线视频| 偷拍自拍在线视频观看| 免费在线观看国内色片网站网址| 五月天黄色激情视频| 狠狠干狠狠色| 亚洲中文字幕妇伦久久| 欧美精品成人亚洲| 97免费视频网| 亚洲麻豆18发?| 91综合网站| 69XX一中文字幕人妻91| 国产精品人人爽人人做可爱福利| 亚洲AV噜噜狠狠网址蜜桃动漫| 亚洲AV无码久久久国产精品| 丁香六月婷婷| 操我啊啊啊啊啊| 色偷综合| 91A欧美电影网站| 一区在线精品中文字幕| 在线岛| 大香蕉九九| 天天综合有色网| 亚洲日韩久久精品一区| 一卡二卡三卡| 人妻一区二区三区视频| 婷婷五月天色色| 精品国产网站|