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

牽著老婆滿街逛

嚴以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

仿函數、綁定、橋接、委托相關討論

from:http://www.gmdev.cn/program/index.html

仿函數、綁定、橋接、委托相關討論:

以下隨便討論下,沒突出的中心論點,個中理論只代表我個人觀點,難免有錯:),歡迎指正。

一。需求:

在事件處理常常會碰到這樣的情況:

1。接口分離。即invokers(調用者)與(receivers)接收者分離。

2。時間分離。

比如說:UI相關元素(按鈕、菜單等)就是一個invokers。

receivers則是響應命令的對象(如對話框或應用程序本身)。

這需要我們要先將UI相關元素的事件響應的接收者在初始化時先保存起來。

待后用戶按下按鈕等再觸發(即invokers通過調用對應先前保存的receivers來執行命令)

嗯,在delphi、java、vcl、.net中有相關的實現。而vc則需要自己來弄。

二。仿函數的實現:

在說仿函數前先說說我們應該怎么保存這些操作相關函數的呢?

// 一般的函數我們可以這么存:

void (*fun)() = Test;

(*fun)();

// 而類成員函數可以這么做:

void (CTest::*mfn)(); // 或用 typedef void (CTest::*MFN_TEST)(); MFN_TEST mfn;

mfn = CTest::Test;

CTest a, *p=new CTest;

(a.*mfn)(); // 調用方法1

(p->*mfn)(); // 調用方法2

如上所述可見為了處理前面所述的事件響應情況,我們通常會用回調函數,

就是把類成員函數定義為靜態函數,在初始時保存函數地址(與一般函數處理類同)及對應的對象指針,

在事件觸發時調用對應的靜態函數,而該函數中在把指針強制轉化為對應類型對象地址,

得以操縱該對象的成員變量(嗯,理論上跟成員函數的實現差不多,成員函數會由編譯器安插一個

this指針作為第1個參數傳給函數,以便可以操作該this對象的成員)。

回調函數應用的具體代碼如下:

1). 回調接口(靜態函數法):

//======================================================

#include "stdafx.h"

#include

typedef void(*KEY_RESPOND)(void* /*,param*/);

struct CListener

{

void* pThis;

KEY_RESPOND pfn;

CListener() : pThis(0), pfn(0){}

};

class CInput

{

std::list m_listListener;

public:

void AddListener( CListener* pListener ){

m_listListener.push_back( pListener );

}

void RemoveListerner( CListener* pListener ){

std::list::iterator iter;

for( iter = m_listListener.begin(); iter!= m_listListener.end();iter++ ){

if( pListener == (*iter) ){

m_listListener.erase( iter ); break;

}

}

}

void HitOneKey(){

std::list::iterator iter;

for( iter = m_listListener.begin(); iter!= m_listListener.end();iter++ ){

if( (*iter)->pfn && (*iter)->pThis ){

(*(*iter)->pfn)( (*iter)->pThis );

}

}

}

void clearListener(){

m_listListener.clear();

}

};

class CUI

{

public:

static void InputProc(void* pThis/*,param*/){

__asm int 3 // 下個斷點測試下(某些編譯器不能這么寫,vc可以)

}

};

CUI ui;

CInput input;

int _tmain(int argc, _TCHAR* argv[])

{

// 初始:

CListener* pListener = new CListener;

pListener->pfn = &CUI::InputProc;

pListener->pThis = &ui;

// 觸發:

input.AddListener( pListener ); // input即為invokers(調用者,但叫觸發者好點)

input.HitOneKey(); // 某處事件觸發,內部呼叫receivers(這里是原先保存的CUI對象)來真正處理該事件(InputProc(...)方法)。

// 清除

input.clearListener();

if( pListener )

{

delete pListener;

pListener = NULL;

}

return 0;

}

//======================================================

// 第2種方法: 回調類(虛函數多態法):

//======================================================

class IWillBack

{

public:

virtual void InputProc(/*參數略...*/){}

};

class CInput

{

public:

void RegisterListener(IWillBack* pListener){

m_pListener = pListener; // 這里用list存起來才好,這里只作測試

}

void OnInputEvent(){

m_pListener->InputProc(/*參數略...*/);

}

private:

IWillBack* m_pListener;

};

class CUI : public IWillBack

{

public:

void InputProc(/*參數略...*/){ /*..實際處理代碼..*/}

private:

};

int _tmain(int argc, _TCHAR* argv[])

{

CInput aa;

CUI bb;

aa.RegisterListener(&bb);

aa.OnInputEvent();

return 0;

}

//======================================================

但是第1種靜態函數用法是不直觀的,第2種需要派生增加了之間的聯系,而為了方便我們通常會將成員函數指針轉化為函數對象來處理,即仿函數(一般是指重載了()操作符的類)來實現。

類似于這樣的操作,stl提供了mem_fun、mem_fun_ref、binder1st、binder2nd簡單操作。

但stl的方法相對比較原始而受限制,比如說std::mem_fun需要成員函數有返回值,

std::mem_fun最多只能支持成員函數有一個參數等,

下面來看std:mem_fun_ref不支持成員函數返回值為void的一個例子:

//======================================================

#include

class CFoo

{

public:

void test() // 只有將void改成別的類型才可以,如:int

{

return 0;

}

};

void main()

{

CFoo t;

std::mem_fun_ref(&CFoo::test)(t);

}

//======================================================

上述代碼只有將void改成別的類型(如int)才可以,

那么為什么不可以處理返回void的函數呢? stl的實現究竟是怎么樣的呢?

嗯,stl簡單實現了mem_fun_ref及mem_fun,其中mem_fun_ref以引用方式處理函數所屬對象,

而mem_fun以指針方式處理函數所屬對象。

現在讓我們從vc的stl挖出部份代碼來看看,

1.stl的實現:

以mem_fun_ref為例(省略某些對說明不重要的細節,兩條虛線包括的代碼為stl類似源碼):

//======================================================

//----------------------------------------------------------

namespace stl_test

{

// 主要實現:

template

class mem_fun_ref_t

{

public:

mem_fun_ref_t( R (T::*_Pm)() ) : _Ptr(_Pm) {} // 構造: 保存成員函數地址

R operator()(T& _X) const // 調用: 這里可看出mem_fun_ref以引用方式處理

{

return ((_X.*_Ptr)()); // 這里執行調用函數,并返回該函數所返回值

}

private:

R (T::*_Ptr)(); // 指向成員函數地址的指針

};

// 這里只是利用函數的參數推導來自動獲取型別(方便調用)

template inline

mem_fun_ref_t mem_fun_ref(R (T::*_Pm)())

{

return (mem_fun_ref_t(_Pm));

}

} // end of namespace test_stl

//----------------------------------------------------------

class CFoo

{

public:

int test1(){

__asm int 3

return 0;

}

void test2(){

__asm int 3

}

};

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

CFoo t;

stl_test::mem_fun_ref( &CFoo::test1 ) (t);

return 0;

}

//======================================================

/////////////////////////////////////////////////////////////////

從源碼"return ((_X.*_Ptr)()); " 可以看到stl直接返回該函數所返回值。

所以函數沒有返回值(即為void時)的話編譯器就會報錯。好,那么如果我們在

這里只是直接執行函數而不用return返回的話編譯器應該可以通過了。

嗯,boost中正是這么處理的。(btw.為了更為通用,boost對stl原有仿函數及綁定作了大量的改進工作)。

但是具體應該怎么區分有沒有返回值呢?這個也容易,我們只需用到模板的偏特性就可

以做到。下面就看看boost的實現(btw.boost有兩種版本,我用的是兼容版本,代碼難看)

2. boost的實現(這里我把boost的一大堆宏(真@$@#@#難看,loki在這方面來得比較清爽)去掉了):

/////////////////////////////////////////////////////////////////

// notreturn.cpp : Defines the entry point for the application.

//

#include "stdafx.h"

//------------------------------------

namespace boost_test

{

template // 有返回值時會調用這個

struct mf

{

template

class inner_mf0

{

R (T::*_Ptr)();

public:

inner_mf0(R (T::*f)()) : _Ptr(f) {}

R operator()(T& X) const

{

return ((X.*_Ptr)());

}

};

};

template<> // 沒有反回值時會調用這個

struct mf // 偏特化

{

template

class inner_mf0

{

R (T::*_Ptr)();

public:

inner_mf0(R (T::*f)()) : _Ptr(f) {}

R operator()(T& X) const

{

((X.*_Ptr)());

}

};

};

// 創建一派生類,派生于上述基類

template

struct mf0 : public mf::inner_mf0

{

typedef R(T::*F)();

explicit mf0(F f) : mf::inner_mf0(f) {}

};

// 通過函數的參數推導自動獲取類型

template

mf0 mem_fn( R(T::*f)() )

{

return mf0(f);

}

} // namespace boost_test

//------------------------------------

class CFoo

{

public:

int test1(){ return 0; }

void test2(){}

};

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

CFoo t;

boost_test::mem_fn( &CFoo::test1 ) (t);

return 0;

}

/////////////////////////////////////////////////////////////////

從上述代碼可以看到偏特性幫助我們解決了返回值為void的情況。但是手寫了兩份

基本相同的代碼。。。

另外處理參數個數的情況也很容易,只要分別實現不同參數的各個模板類就可以了,

boost最多只能支持成員函數有8個參數,因為它內部實現了8份這樣不同參數模板類。

其實的處理方法都是一模一樣的,可是由于語言的限制我們還是沒有辦法不一一實現

不同參數的類:。在loki中參數可以用TList實現任意的參數,但是在實現還是得老

老實實的每份手寫一份(loki實現了15份可以支持15個參數)。

這真讓人郁悶。。。不過沒辦法。

說完來仿函數,下面開始說說有關綁定,stl、boost、loki的綁定的意思是

對某物實體的“綁定”,通俗來說是指對函數、構造函數、仿函數等與其對應的某個參數的綁定,

以便在調用時不用再次輸入此參數(因為某些時候參數是固定的,比如說綁定一個內部存有

成員函數地址的仿函數和它對應的對象地址在一起)。

以下是stl的bind用法:

//================================

#include "stdafx.h"

#include // stl

#include // boost

struct CFoo {

int test(int){

return 0;

}

};

void main()

{

boost::function1 f; // 這里用了boost

CFoo obj;

f = std::bind1st(std::mem_fun(&CFoo::test), &obj);

f(5);

}

//================================

loki中的BindFirst比較類似于stl的binder

(binder1st,binder2nd),但是它是通用的,可以通過嵌套實現任意多個參數綁定:

//================================

void f()

{

Functor cmd1(something);

Functor cmd2(BindFirst(cmd1, 10));

cmd2(20);

Functor cmd3(BindFirst(cmd2, 30));

cmd3();

}

而boost中的實現是以占位符來表現,具體如何實現,下回繼續討論(嗯,

boost代碼的宏太多了,這部份還是等有空再補全了,現在我們來看看如何實現一個委托類)

三。委托類的實現:

1. 橋接模式:

設計模式告訴我們可以使用橋接模式(Bridge Pattern)減少對象之間的 耦合度,橋接模式如下:

Invoker <>------------------->* Interface

^

|

Receiver

上圖的Invoker表示事件觸發者,Receiver表示事件處理者,符號類似于<c++大規模編程。。>一書所描述(注:這里符號對位可能出錯:變成左對齊了),

其中<>------------------->表示Invoker 內含(擁用)Interface(即Invoker 有Interface的變量或指針并負責Interface的釋放),

而*號表示可有多個。

^

| 號則表示繼承于(Receiver繼承于Interface)。

好,我們先來分析前面在" 第2種方法: 回調類(虛函數多態法):"的實現思想(請回到前面看看代碼),

它其實就是一個橋接模式,如下(括號內對應前面所實現的類):

Invoker(CInput) <>--------------->* Interface(IWillBack)

^

|

Receiver(CUI)

對照我們前面實現的代碼可以發現此種實現的橋接的缺點是:每一個想要

注冊一方法到Invoker中以便Invoker在事件觸發時調用的類(如Receiver)都要派生自Interface。

有沒有更好的辦法再次減少這種耦合度呢?這正是下面我們要討

論的下一種設計模式:

2. 委托與事件:

委托的處理設計如下:

Invoker <>--------------------->* Interface

^

|

Implementation -----------------> Receiver

即在原橋接模式下再加一層間接性:Implementation 。其中

Implementation與Receiver之間的----------------->表示Implementation引用了Receiver一些服務,

即Implementation用到了Receiver某些東西(如函數或數據)。嗯,這些解釋不知是否適當,希望不會誤導。。。

好,一開始可能我們會這么設計:

//======================================================================================

class handle {};

template

class Implementation : public handle

{

T* m_pThis;

public:

Implementation ( T* pThis ) : m_pThis(pThis) {}

template

void execute( void (T::*mfn)(T1), T1 arg ) { (m_pThis->*mfn)( arg ); }

};

struct Receive {

void Proc(int) {

__asm int 3

}

};

Receive a;

void Invoker(){

Implementation test = Implementation (&a);

test.execute( Receive::Proc, 10 ); // 當事件發生時調用

};

int _tmain(int argc, _TCHAR* argv[])

{

Invoker();

}

//======================================================================================

但是Invoker知道了太多Receive的信息,況且我們想讓觸發者Invoker作成一個類。

一個改進的版本如下:

//-------------------------------------------------------------

// signal slot system

// 注: 該法我是看了"落木隨風"的"委托、信號和消息反饋的模板實現技術",

// 代碼作了部份添加。在這里非常的感謝他!

// 他的博客:http://blogs.gcomputing.com/rocwood/archives/000154.html

//-------------------------------------------------------------

// Delegation.cpp : Defines the entry point for the console application.

//

#include

#ifndef K_DELEGATE_H

#define K_DELEGATE_H

namespace kUTIL

{

// 1. 橋接類(純虛類):

// 為什么叫作橋接?

// 因為通過它的虛函數方法可以調用到對應的正確的不同派生實例(指后面

// 提到的委托人)所改寫的虛函數方法(這是委托人用來完成委托任務的方法)

struct kDelegationInterface

{

virtual ~kDelegationInterface() {};

virtual void Execute() = 0;

};

// 2. 委托類(派生于橋接類,這里我叫為”委托人“)

// 為什么叫委托?

// 因為調用者把“通知”的工作委托給它來負責處理。

// 一個“委托人”保存了: a.”接收者“(對象指針m_pThis) 及 b.“要作的事”(方法指針m_mfn),

// 以便調用者發出信號彈(后面提到,信號彈有一個作橋接用的純虛類的指針指向相應的委托人)

// 告知此信號對應的委托人來完成它被委托的工作:即讓“接收者”(m_pThis)作”要作的事“(m_mfn)。

 

template

struct kDelegationImpl : public kDelegationInterface

{

typedef 
void ( T::* MFN )();

kDelegationImpl( T
* pthis, MFN mfn ) : m_pThis( pthis ), m_mfn( mfn ) {

}


virtual void Execute() {

if( m_pThis ) 

( m_pThis
->*m_mfn )(); 

}


}


T
* m_pThis;

MFN m_mfn;

}
;

 

// 3. 信號彈(實現為仿函數來調用統一的虛函數接口):

// 為什么叫信號?

// 因為當"信號彈"發射時(調用信號的操作符"()")

// 它會通知所指向的"委托人"事件發生了(調用純虛類指針的m_DI->Execute()方法)。

// 一個信號保存了一個指向對應”委托人“的橋接類(純虛類)指針。

 

struct kSignal0

{

kDelegationInterface
* m_DI; // 純虛類的指針

kSignal0() : m_DI(
0{}

 

// 1. 純虛類的m_DI指針可以指向不同的派生實例:

 

template

void ConnectSlot(T* recv, void (T::* mfn)()) {

DisConnect();

m_DI 
= new kDelegationImpl( recv, mfn );

int test = 0;

}


void DisConnect() {

if( m_DI ) { delete m_DI; m_DI = NULL; }

}

 

// 2. 用統一的純虛類指針調用不同派生類改寫的虛函數

 

void operator() () 

if( m_DI ) {

m_DI
->Execute(); 

}


}


};

 

// 下面是兩個為方便使用的函數:

 

template

void kConnect( kSignal0& sgn, T* pObj, void(T::*fn)())

{

sgn.ConnectSlot( pObj, fn );

int i = 0;

}


inline 
void kDisConnect( kSignal0& sgn )

{

sgn.DisConnect();

}


// end of namespace kUTIL

#endif //#ifndef K_DELEGATE_H

 

 

//----------------------------------------------------------------------------

// 一個使用實例:

class kButton {

public:

kUTIL::kSignal0 sgnMouseBtnUp;

void OnMouseButtonUp() { sgnMouseBtnUp(); }

}
;

class kDialog {

kButton btn;

public:

kDialog() 
{

kUTIL::kConnect( btn.sgnMouseBtnUp, 
this&kDialog::DoWork ); // vc6下這里kDialog::DoWork的前面一定要可加"&"號

}


void DoWork() 

__asm 
int 3

}


void TestMouseHit() { btn.OnMouseButtonUp(); }

}
;

int main(int argc, char* argv[])

{

kDialog dlg;

kButton btn;

kUTIL::kConnect( btn.sgnMouseBtnUp, 
&dlg, kDialog::DoWork ); // vc6下這里kDialog::DoWork的前面可加/不加"&"號

// 測試一:



// 測試二:

dlg.TestMouseHit();

return 0;

}

 

 

// 委托實例總結:

// 下面我們來具體說明”當某事發生時,調用者發射信號彈通知對應的接收者作相應處理“

// 1. "調用者" 擁有各種信號彈。

// 2. 初始時,我們把信號彈與對應的委托人聯系起來,并讓委托人記錄在信號觸發時應該通知的"接收人"和"接收人該作的事"。

// a. 信號彈保存了橋(純虛類)指針,指針指向通過其模板函數ConnectSlot方法來找出(產生的)委托人(委托實例)。

// b. 委托人(委托實例)在信號彈用ConnectSlot方法產生它的時候保存了函數ConnectSlot所傳入的兩個參數:

// 即"接收者指針"及"其方法指針"。

// 3. 當事件發生時"調用者"發射對應信號彈后,信號彈會調用其所保存的純虛類指針的虛函數方法,

// 于是由于虛函數特性就會調用到其所指向的委托實例(委托人)所改寫的方法。

// 5. 委托人改寫的方法中通過其所保存的”接收者指針“及其"方法指針"來呼叫"接收者"用對應的”方法指針“

// 來處理事情。

// 即如下流程:

// "調用者"發射"信號彈" ---> "信號彈"通過"橋"找到對應"委托人" ---> "委托人"呼叫"接收者"作"該作的事"

//=============================================================================

嗯,這樣到此,一個非常方便的委托類就得以實現了!如果你還不懂的話請仔細的琢磨,如此精華(因為簡單而強大)

不要錯過。不過上述只是部份實現,當你要支持帶參數及返回值的各種情況的話,還得自己作擴充。

返回值的處理方法可參見前面剖述boost的mem_fn的處理方法,而帶不同參數的處理則只能一一手動

實現,就象前面所說的那樣,這是很無奈的事情,但是目前來說沒有辦法。。。

(待續。。。。。。,如果有時間有必要的話。。。)

附:

loki下載:

http://sourceforge.net/projects/loki-lib/

boost下載:

http://sourceforge.net/projects/boost/

2004.10.26更新:

修正:

原void connect( Signal0& sgn,T1 obj, void(T2::*fn)())改成

void connect( Signal0& sgn,T1& obj, void(T2::*fn)())

另外加了kDisConnect釋放內存,原來只作測試沒寫它,現在還是加上了。

posted on 2007-09-03 15:22 楊粼波 閱讀(504) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            黑人一区二区三区四区五区| 久久野战av| 欧美va天堂| 国产亚洲一区二区三区在线播放| 亚洲美女视频在线免费观看| 玖玖精品视频| 久久综合伊人| 久久久精品免费视频| 新67194成人永久网站| 亚洲综合国产| 午夜精品久久久久久久99水蜜桃| 欧美1区免费| 久久久久久久久综合| 午夜天堂精品久久久久| 亚洲精品国产拍免费91在线| 欧美日韩伦理在线| 欧美区高清在线| 欧美精品一区二| 欧美性片在线观看| 国产乱子伦一区二区三区国色天香| 欧美性久久久| 国产亚洲视频在线观看| 国产一区二区三区高清| 欧美午夜一区二区三区免费大片| 欧美午夜精品一区二区三区| 国产精品一区久久| 国产亚洲二区| 亚洲国产天堂网精品网站| 亚洲精品欧美在线| 亚洲视频在线看| 久久精品综合| 欧美激情第8页| 亚洲国产一区二区三区高清| 欧美岛国在线观看| 欧美fxxxxxx另类| 日韩视频一区二区| 午夜视频一区| 久久综合99re88久久爱| 久久精品官网| 国产日韩欧美在线视频观看| 国产精品裸体一区二区三区| 亚洲激情视频网站| 99精品国产在热久久婷婷| 在线一区欧美| 亚洲香蕉成视频在线观看 | 久久亚洲二区| 欧美99在线视频观看| 亚洲欧洲日产国产综合网| 亚洲一区二区三区高清| 久久婷婷久久| 国产精品中文字幕在线观看| 亚洲欧美另类在线| 欧美电影在线免费观看网站| 欧美人妖在线观看| 娇妻被交换粗又大又硬视频欧美| 亚洲精品美女| 久久久噜噜噜久久狠狠50岁| 一区二区三区视频在线观看| 毛片基地黄久久久久久天堂| 国产一区二区三区成人欧美日韩在线观看| 91久久综合| 久久久久久亚洲精品杨幂换脸 | 免费在线成人av| 99亚洲精品| 欧美国产高潮xxxx1819| 激情视频一区| 久久精品99国产精品酒店日本| 美日韩精品免费| 亚洲欧洲在线免费| 免费观看成人鲁鲁鲁鲁鲁视频| 国产午夜精品理论片a级大结局| 亚洲视频一区二区| 亚洲精品影院在线观看| 欧美插天视频在线播放| **欧美日韩vr在线| 久久免费一区| 久久成人资源| 国产一区二区三区日韩欧美| 午夜亚洲福利| 亚洲欧美日韩在线一区| 欧美精品久久一区二区| 国产丝袜美腿一区二区三区| 欧美一区三区二区在线观看| 亚洲欧美精品中文字幕在线| 国产欧美一区二区色老头| 欧美在线视频一区| 欧美一区二区精品| 国产亚洲欧美日韩美女| 久久久久国产免费免费| 含羞草久久爱69一区| 国内自拍亚洲| 久久免费精品视频| 久久久久青草大香线综合精品| 国内精品国语自产拍在线观看| 久久精品视频网| 久久裸体视频| 亚洲欧洲美洲综合色网| 日韩视频中午一区| 免费成人毛片| 国语自产在线不卡| 亚洲电影观看| 欧美日韩国语| 性感少妇一区| 久久久久国产精品午夜一区| 亚洲激情精品| 亚洲综合电影一区二区三区| 国产一区二区三区精品欧美日韩一区二区三区 | 欧美日本韩国| 亚洲视频高清| 中文在线资源观看网站视频免费不卡 | 欧美日韩精品一区二区三区| 亚洲免费av观看| 中文在线不卡视频| 欧美激情第10页| 亚洲精品美女久久久久| 亚洲视屏一区| 亚洲国产精品第一区二区三区 | 在线电影院国产精品| 久久久999国产| 欧美成人乱码一区二区三区| 亚洲欧美日韩精品久久| 久久免费视频网站| 一区二区三区蜜桃网| 欧美一区二区三区成人| 日韩午夜视频在线观看| 欧美在线三区| 在线亚洲自拍| 亚洲综合第一| 国产一区二区av| 亚洲第一中文字幕在线观看| 国产欧美一区二区精品性色| 亚洲国产1区| 国内外成人免费激情在线视频| 亚洲人成网站在线观看播放| 国产亚洲一区精品| 欧美精品在线一区| 狼狼综合久久久久综合网| 欧美一区二区三区喷汁尤物| 一区二区福利| 男同欧美伦乱| 久久久99精品免费观看不卡| 欧美日韩综合在线| 欧美黄色成人网| 狠狠做深爱婷婷久久综合一区| 亚洲综合二区| 久久福利资源站| 红桃视频亚洲| 欧美aⅴ一区二区三区视频| 亚洲国产精品一区| 一区二区三区免费看| 欧美无乱码久久久免费午夜一区| 一区二区三区色| 欧美一区二区日韩| 伊人精品久久久久7777| 免费在线亚洲| 99国产精品久久久久久久| 亚洲欧美日韩综合aⅴ视频| 国产精品亚洲综合久久| 欧美在线观看日本一区| 国产精品区一区二区三区| 欧美亚洲视频| 快播亚洲色图| 一区二区精品| 欧美aⅴ一区二区三区视频| 亚洲娇小video精品| 亚洲欧美日韩国产中文| 在线欧美一区| 欧美午夜大胆人体| 久久精品人人爽| 亚洲美洲欧洲综合国产一区| 欧美综合国产精品久久丁香| 亚洲国产精品一区二区久| 欧美日韩亚洲一区二区| 久久精品国产综合精品| 亚洲精品综合久久中文字幕| 久久精品123| 一区二区三区福利| 狠狠网亚洲精品| 欧美无乱码久久久免费午夜一区| 欧美中文字幕久久| 日韩亚洲在线观看| 免费一区视频| 欧美一区二区三区精品电影| 亚洲精品视频免费观看| 国产一区二区丝袜高跟鞋图片| 欧美国产日韩精品| 欧美一区二区三区男人的天堂 | 国产精品ⅴa在线观看h| 久久亚洲视频| 亚洲综合999| 一本到12不卡视频在线dvd| 乱码第一页成人| 欧美中文在线观看国产| 中文国产亚洲喷潮| 亚洲精品少妇网址| 在线不卡中文字幕| 国产最新精品精品你懂的| 国产精品网站在线观看| 国产精品成人久久久久| 欧美日韩精品福利|