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

woaidongmao

文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見(jiàn)諒!~
隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
數(shù)據(jù)加載中……

直接調(diào)用類成員函數(shù)地址

下載源代碼

摘要:介紹了如何取成員函數(shù)的地址以及調(diào)用該地址.

關(guān)鍵字:C++成員函數(shù) this指針 調(diào)用約定

一、成員函數(shù)指針的用法

  在C++中,成員函數(shù)的指針是個(gè)比較特殊的東西。對(duì)普通的函數(shù)指針來(lái)說(shuō),可以視為一個(gè)地址,在需要的時(shí)候可以任意轉(zhuǎn)換并直接調(diào)用。但對(duì)成員函數(shù)來(lái)說(shuō),常規(guī)類型轉(zhuǎn)換是通不過(guò)編譯的,調(diào)用的時(shí)候也必須采用特殊的語(yǔ)法。C++專門為成員指針準(zhǔn)備了三個(gè)運(yùn)算符: "::*"用于指針的聲明,而"->*"".*"用來(lái)調(diào)用指針指向的函數(shù)。比如:

   class tt
   {
       public: void foo(int x){ printf("\n %d \n",x); }
   };
 
   typedef   void  ( tt::* FUNCTYPE)(int );
 
 
    FUNCTYPE ptr = tt::foo;  //給一個(gè)成員函數(shù)指針賦值.
 
    tt a;
    (a.*ptr)(5);   //調(diào)用成員函數(shù)指針.
 
    tt *b = new tt;
    (b->*ptr)(6);  //調(diào)用成員函數(shù)指針.


  注意調(diào)用函數(shù)指針時(shí)括號(hào)的用法,因?yàn)?span lang="EN-US"> .* ->* 的優(yōu)先級(jí)比較低,必須把它們和兩邊要結(jié)合的元素放到一個(gè)括號(hào)里面,否則通不過(guò)編譯。不僅如此,更重要的是,無(wú)法為成員函數(shù)指針進(jìn)行任何的類型轉(zhuǎn)換,比如你想將一個(gè)成員函數(shù)的地址保存到一個(gè)整數(shù)中(就是取類成員函數(shù)的地址),按照一般的類型轉(zhuǎn)換方法是辦不到的.下面的代碼:

    DWORD dwFooAddrPtr= 0;
    dwFooAddrPtr = (DWORD) &tt::foo;  /* Error C2440 */
    dwFooAddrPtr = reinterpret_cast (&tt::foo); /* Error C2440 */

  你得到只是兩個(gè)c2440錯(cuò)誤而已。當(dāng)然你也無(wú)法將成員函數(shù)類型轉(zhuǎn)換為其它任何稍有不同的類型,簡(jiǎn)單的說(shuō),每個(gè)成員函數(shù)指針都是一個(gè)獨(dú)有的類型,無(wú)法轉(zhuǎn)換到任何其它類型。即使兩個(gè)類的定義完全相同也不能在其對(duì)應(yīng)成員函數(shù)指針之間做轉(zhuǎn)換。這有點(diǎn)類似于結(jié)構(gòu)體的類型,每個(gè)結(jié)構(gòu)體都是唯一的類型,但不同的是,結(jié)構(gòu)體指針的類型是可以強(qiáng)制轉(zhuǎn)換的。有了這些特殊的用法和嚴(yán)格的限制之后,類成員函數(shù)的指針實(shí)際上是變得沒(méi)什么用了。這就是我們平常基本看不到代碼里有"::*", ".*" "->*"的原因。

二、取成員函數(shù)的地址

  當(dāng)然,引用某位大師的話:"windows中,我們總是有辦法的"。同樣,在C++中,我們也總是有辦法的。這個(gè)問(wèn)題,解決辦法已經(jīng)存在了多年,并且廣為使用(在MFC中就使用了)。一般有兩個(gè)方法,一是使用內(nèi)嵌的匯編語(yǔ)言直接取函數(shù)地址,二是使用union類型來(lái)逃避C++的類型轉(zhuǎn)換檢測(cè)。兩種方法都是利用了某種機(jī)制逃避C++的類型轉(zhuǎn)換檢測(cè),為什么C++編譯器干脆不直接放開(kāi)這個(gè)限制,一切讓程序員自己作主呢?當(dāng)然是有原因的,因?yàn)轭惓蓡T函數(shù)和普通函數(shù)還是有區(qū)別的,允許轉(zhuǎn)換后,很容易出錯(cuò),這個(gè)在后面會(huì)有詳細(xì)的說(shuō)明。現(xiàn)在先看看取類成員函數(shù)地址的兩種方法:

第一種方法:

template 
void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
{
    union 
    {
      FromType _f;
      ToType   _t;
    }ut;
 
    ut._f = f;
 
    addr = ut._t;
}


這樣使用:

DWORD dwAddrPtr;

GetMemberFuncAddr_VC6(dwAddrPtr,&tt::foo);

  為什么使用模版? 呵呵,如果不使用模版,第二個(gè)參數(shù)該怎么些,寫成函數(shù)指針且不說(shuō)太繁瑣,關(guān)鍵是沒(méi)有通用性,每個(gè)成員函數(shù)都要單獨(dú)寫一個(gè)轉(zhuǎn)換函數(shù)。

第二種方法:

#define GetMemberFuncAddr_VC8(FuncAddr,FuncType)\
{                                               \
    __asm                                       \
    {                                           \
        mov eax,offset FuncType                 \
    };                                          \
    __asm                                       \
    {                                           \
        mov FuncAddr, eax                       \
    };                                          \
}
 

這樣使用:

DWORD dwAddrPtr;

GetMemberFuncAddr_VC8(dwAddrPtr,&tt::foo);

  本來(lái)是想寫成一個(gè)模版函數(shù)的,可惜雖然通過(guò)了編譯,卻不能正確運(yùn)行。估計(jì)在匯編代碼中使用模版參數(shù)不太管用,用offset取偏移量直接就得0
  上面的宏是可以正確運(yùn)行的,并且還有一個(gè)額外的好處,就是可以直接取私有成員函數(shù)的地址(大概在asm括號(hào)中,編譯器不再檢查代碼的可訪問(wèn)性)。不過(guò)缺點(diǎn)是它在vc6下是無(wú)法通過(guò)編譯的,只能在VC8下使用。

三、調(diào)用成員函數(shù)地址

  通過(guò)上面兩個(gè)方法,我們可以取到成員函數(shù)的地址。不過(guò),如果不能通過(guò)地址來(lái)調(diào)用成員函數(shù)的話,那也還是沒(méi)有任何用處。當(dāng)然,這是可行的。不過(guò)在這之前,需要了解關(guān)于成員函數(shù)的一些知識(shí)。
  我們知道,成員函數(shù)和普通函數(shù)最大的區(qū)別就是成員函數(shù)包含一個(gè)隱藏的參數(shù)this指針,用來(lái)表明成員函數(shù)當(dāng)前作用在那一個(gè)對(duì)象實(shí)例上。根據(jù)調(diào)用約定(Calling Convention)的不同,成員函數(shù)實(shí)現(xiàn)this指針的方式也不同。如果使用__thiscall調(diào)用約定,那么this指針保存在寄存器ECX中,VC編譯器缺省情況下就是這樣的。如果是__stdcall__cdecl調(diào)用約定,this指針將通過(guò)棧進(jìn)行傳遞,且this指針是最后一個(gè)被壓入棧的參數(shù),相當(dāng)于編譯器在函數(shù)的參數(shù)列表中最左邊增加了一個(gè)this參數(shù)。
  這里還有件事不得不提,雖然vc__thiscall類型作為成員函數(shù)的默認(rèn)類型,但是vc6卻沒(méi)有定義__thiscall關(guān)鍵字!如果你使用__thiscall來(lái)定義一個(gè)函數(shù),編譯器報(bào)錯(cuò):'__thiscall' keyword reserved for future use

知道這些就好辦了,我們只要根據(jù)不同的調(diào)用約定,準(zhǔn)備好this指針,然后象普通函數(shù)指針一樣的使用成員函數(shù)地址就可以了。

  對(duì)__thiscall類型的成員函數(shù)(注意,這個(gè)是VC的默認(rèn)類型),我們?cè)谡{(diào)用之前加一句: mov ecx, this; 然后就可以調(diào)用成員函數(shù)指針。例如:

class tt 
{
 public:
 
    void foo(int x,char c,char *s)//沒(méi)有指定類型,默認(rèn)是__thiscall.
    {
        printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
    }
 
    int m_a;
};
 
typedef  void (__stdcall *FUNCTYPE)(int x,char c,char *s);//定義對(duì)應(yīng)的非成員函數(shù)指針類型,注意指定__stdcall.
 
 
    tt abc;
    abc.m_a = 123;
 
    DWORD ptr;
    DWORD This = (DWORD)&abc;
 
    GetMemberFuncAddr_VC6(ptr,tt::foo); //取成員函數(shù)地址.
 
    FUNCTYPE fnFooPtr  = (FUNCTYPE) ptr;//將函數(shù)地址轉(zhuǎn)化為普通函數(shù)的指針. 
 
    __asm //準(zhǔn)備this指針.
    {
        mov ecx, This;
    }
 
    fnFooPtr(5,'a',"7xyz"); //象普通函數(shù)一樣調(diào)用成員函數(shù)的地址.


  對(duì)其它類型的成員函數(shù),我們只要申明一個(gè)與原成員函數(shù)定義完全類似的普通函數(shù)指針,但在參數(shù)中最左邊加一個(gè)void * 參數(shù)。代碼如下:

class tt 
{
 
public:
 
    void __stdcall foo(int x,char c,char *s)//成員函數(shù)指定了__stdcall調(diào)用約定.
    {
        printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
    }
 
    int m_a;
};
 
typedef  void (__stdcall *FUNCTYPE)(void *This,int x,char c,char *s);//注意多了一個(gè)void *參數(shù).
 
    tt abc;
    abc.m_a = 123;
 
    DWORD ptr;
 
    GetMemberFuncAddr_VC6(ptr,tt::foo); //取成員函數(shù)地址.
 
    FUNCTYPE fnFooPtr = (FUNCTYPE) ptr;//將函數(shù)地址轉(zhuǎn)化為普通函數(shù)的指針. 
 
    fnFooPtr(&abc,5,'a',"7xyz"); //象普通函數(shù)一樣調(diào)用成員函數(shù)的地址,注意第一個(gè)參數(shù)是this指針.

  每次都定義一個(gè)函數(shù)類型并且進(jìn)行一次強(qiáng)制轉(zhuǎn)化,這個(gè)事是比較煩的,能不能將這些操作寫成一個(gè)函數(shù),然后每次調(diào)用是指定函數(shù)地址和參數(shù)就可以了呢?當(dāng)然是可以的,并且我已經(jīng)寫了一個(gè)這樣的函數(shù)。

//調(diào)用類成員函數(shù)
//callflag:成員函數(shù)調(diào)用約定類型,0--thiscall,0--其它類型.
//funcaddr:成員函數(shù)地址.
//This:類對(duì)象的地址.
//count:成員函數(shù)參數(shù)個(gè)數(shù).
//...:成員函數(shù)的參數(shù)列表.
DWORD CallMemberFunc(int callflag,DWORD funcaddr,void *This,int count,...)
{
      DWORD re;
 
      if(count>0)//有參數(shù),將參數(shù)壓入棧.
      {
           __asm
           {
                 mov  ecx,count;//參數(shù)個(gè)數(shù),ecx,循環(huán)計(jì)數(shù)器.
                 mov  edx,ecx;
                 shl  edx,2;    
                 add  edx,0x14;  edx = count*4+0x14;
 
        next:    push  dword ptr[ebp+edx];
                 sub   edx,0x4;
                 dec   ecx  
                 jnz   next;
           }
      }
 
      //處理this指針.
      if(callflag==0) //__thiscall,vc默認(rèn)的成員函數(shù)調(diào)用類型.
      {
           __asm mov ecx,This;
      }
      else//__stdcall
      {
           __asm push This;
      }
 
      __asm//調(diào)用函數(shù)
      {
           call funcaddr;
           mov  re,eax;
      }
 
      return re;
}

使用這個(gè)函數(shù),則上面的兩個(gè)調(diào)用可以這樣寫:

CallMemberFunc(0,ptr1,&abc,3,5,'a',"7xyz");//
第一個(gè)參數(shù)0,表示采用__thiscall調(diào)用.

CallMemberFunc(1,ptr2,&abc,3,5,'a',"7xyz");//
第一個(gè)參數(shù)1,表示采用非__thiscall調(diào)用.

  需要說(shuō)明的是,CallMemberFunc是有很多限制的,它并不能對(duì)所有的情況都產(chǎn)生正確的調(diào)用序列。原因之一是它假定每個(gè)參數(shù)都使用了4個(gè)字節(jié)的棧空間。這在大多數(shù)情況下是正確的,比如參數(shù)為指針,char,short,int,long以及對(duì)應(yīng)的無(wú)符號(hào)類型,這些參數(shù)確實(shí)都是每一個(gè)參數(shù)使用了4字節(jié)的棧空間。但是還有很多情況下,參數(shù)不使用4字棧空間,比如double,自定義的結(jié)構(gòu)或類.float雖然是占了4字節(jié),但編譯器還產(chǎn)生了一些浮點(diǎn)指令,而這些無(wú)法在CallMemberFunc被模擬出來(lái),因此對(duì)float參數(shù)也是不行的。
  總結(jié)一下,如果成員函數(shù)的參數(shù)都是整型兼容類型,則可以使用CallMemberFunc調(diào)用函數(shù)地址。如果不是,那就只有按前面的方法,先定義對(duì)應(yīng)的普通函數(shù)類型,強(qiáng)制轉(zhuǎn)化,準(zhǔn)備this指針,然后調(diào)用普通函數(shù)指針。

四、進(jìn)一步的討論

  到目前為止,已經(jīng)討論了如何取成員函數(shù)的地址,然后如何使用這個(gè)地址。但是還有些重要的情況沒(méi)有討論,我們知道成員函數(shù)可分為三種:普通成員函數(shù),靜態(tài),虛擬。另外更重要的是,在繼承甚至多繼承下情況如何。

首先看看最簡(jiǎn)單的單繼承,非虛擬函數(shù)的情況。
 

class tt1
{
public:
      void foo1(){ printf("\n hi, i am in tt1::foo1\n"); }
};
 
class tt2 : public tt1
{
public:
      void foo2(){ printf("\n hi, i am in tt2::foo2\n"); }
};

注意,tt2中沒(méi)有定義函數(shù)foo1,它的foo1函數(shù)是從tt1中繼承過(guò)來(lái)的。這種情況下,我們直接取tt2::foo1的地址行會(huì)發(fā)生什么?

DWORD tt2_foo1;
tt1 x;
 
GetMemberFuncAddr_VC6(tt2_foo1,&tt2::foo1);
CallMemberFunc(0,tt2_foo1,&x,0); // tt2::foo1 = tt1::foo1

  運(yùn)行結(jié)果表明,一切正常!當(dāng)我們寫下tt2::foo1的時(shí)候,編譯器知道那實(shí)際上是tt1::foo1,因此它會(huì)暗中作替換。編譯器(VC6)產(chǎn)生的代碼如下:

GetMemberFuncAddr_VC6(tt2_foo1,&tt2::foo1); //源代碼.
 
//VC6編譯器產(chǎn)生的匯編代碼:
 
push offset @ILT+235(tt1::foo1) (004010f0) //直接用tt1::foo1 替換 tt2::foo1.
...

再看看稍微復(fù)雜些的情況,繼承情況下的虛擬函數(shù)。

class tt1
{
public:
      void foo1(){ printf("\n hi, i am in tt1::foo1\n"); }
      virtual void foo3(){ printf("\n hi, i am in tt1::foo3\n"); }
};
 
class tt2 : public tt1
{
public:
      void foo2(){ printf("\n hi, i am in tt2::foo2\n"); }
      virtual void foo3(){ printf("\n hi, i am in tt2::foo3\n"); }
};

現(xiàn)在tt1tt2都定義了虛函數(shù)foo3,按C++語(yǔ)法,如果通過(guò)指針調(diào)用foo3,應(yīng)該發(fā)生多態(tài)行為。下面的代碼:

DWORD tt1_foo3,tt2_foo3;
 
GetMemberFuncAddr_VC6(tt1_foo3,&tt1::foo3);
GetMemberFuncAddr_VC6(tt2_foo3,&tt2::foo3);
 
tt1 x;
tt2 y;
 
CallMemberFunc(0,tt1_foo3,&x,0); // tt1::foo3
CallMemberFunc(0,tt2_foo3,&x,0); // tt2::foo3
 
CallMemberFunc(0,tt1_foo3,&y,0); // tt1::foo3
CallMemberFunc(0,tt2_foo3,&y,0); // tt2::foo3

輸出如下:

hi, i am in tt1::foo3
hi, i am in tt1::foo3
hi, i am in tt2::foo3
hi, i am in tt2::foo3

  請(qǐng)注意第二行輸出,tt2_foo3取的是&tt2::foo3,但由于傳遞的this指針產(chǎn)生是&x,所以實(shí)際上調(diào)用了tt1::foo3。同樣,第三行輸出,取的是基類的函數(shù)地址,但由于實(shí)際對(duì)象是派生類,最后調(diào)用了派生類的函數(shù)。這說(shuō)明取得的成員函數(shù)地址在虛擬函數(shù)的情況下仍然保持了正確的行為。
  你若真的理解了上面所說(shuō)的,一定會(huì)覺(jué)得奇怪。取函數(shù)地址的時(shí)候就得到了一個(gè)整數(shù)(成員函數(shù)地址),為何調(diào)用的時(shí)候卻進(jìn)了不同的函數(shù)? 只要看看匯編代碼就都清楚了,"源碼之前,了無(wú)秘密"。源代碼: GetMemberFuncAddr_VC6(tt1_foo3,&tt1::foo3); 產(chǎn)生的匯編代碼如下:

push offset @ILT+90(`vcall') (0040105f)
...

  原來(lái)取tt1::foo3地址的時(shí)候,并不是真的就將tt1::foo3的地址傳給了函數(shù),而是傳了一個(gè)vcall函數(shù)的地址。顧名思義,vcall當(dāng)然是虛擬調(diào)用的意思。我們找到地址0040105f,看看這個(gè)函數(shù)到底干了些什么。

@ILT+90(??_9@$BA@AE):
0040105F jmp `vcall' (00401380)

該地址只是ILT的一個(gè)項(xiàng),直接跳轉(zhuǎn)到真正的vcall函數(shù),00401380。找到00401380,就可以看到vcall的代碼。

`vcall':
00401380 mov eax,dword ptr [ecx] ;//this指針視為dword類型,并將指向的內(nèi)容(對(duì)象的首個(gè)dword)放入eax.
00401382 jmp dword ptr [eax] ;//跳轉(zhuǎn)到eax所指向的地址.

  代碼執(zhí)行的時(shí)候,ecx就是this指針,具體說(shuō)就是上面對(duì)象xy的地址。而eax就是對(duì)象xy的第一個(gè)dword的值。我們知道,對(duì)于有虛擬函數(shù)的類對(duì)象,其對(duì)象的首地址處總是一個(gè)指針,該指針指向一個(gè)虛函數(shù)的地址表。上面的對(duì)象由于只有一個(gè)虛函數(shù),所以虛函數(shù)表也只有一項(xiàng)。因此,直接跳轉(zhuǎn)到eax指向的地址就好。如果有多個(gè)虛函數(shù),則eax還要加上一個(gè)偏移量,以定位到不同的虛函數(shù)。比如,如果有兩個(gè)虛函數(shù),則會(huì)有兩個(gè)vcall代碼,分別對(duì)應(yīng)不同的虛函數(shù),其代碼大概是下面的樣子:

`vcall':
00401BE0 mov eax,dword ptr [ecx]
00401BE2 jmp dword ptr [eax]
 
`vcall':
00401190 mov eax,dword ptr [ecx]
00401192 jmp dword ptr [eax+4]

編譯器根據(jù)取的是哪個(gè)虛函數(shù)的地址,則相應(yīng)的用對(duì)應(yīng)的vcall地址代替。

  總結(jié)一下:用前面方法取得的成員函數(shù)地址在虛擬函數(shù)的情況下仍然保持正確的行為,是因?yàn)榫幾g器實(shí)際上傳遞了對(duì)應(yīng)的vcall地址。而vcall代碼會(huì)根據(jù)上下文this指針定位到對(duì)應(yīng)的虛函數(shù)表,進(jìn)而調(diào)用正確的虛函數(shù)。
  最后,我們看一下多繼承情況。很明顯,現(xiàn)在情況要復(fù)雜得多。如果實(shí)際試一下,會(huì)碰到很多困難。首先,指定成員函數(shù)的時(shí)候可能會(huì)碰到?jīng)_突。其次,給定this指針的時(shí)候需要經(jīng)過(guò)調(diào)整。另外,對(duì)虛擬繼承可能還要特別處理。解決所有這些問(wèn)題已經(jīng)超出了這篇文章的范圍,并且我想要的成員函數(shù)指針是一個(gè)真正的指針,而在多繼承的情況下,很多時(shí)候成員函數(shù)指針已經(jīng)變成了一個(gè)結(jié)構(gòu)體(見(jiàn)參考文獻(xiàn)),這時(shí)要正確調(diào)用該指針就變得格外困難。因此結(jié)論是,上面討論的方法并不適用于多繼承的情況,要想在多繼承的情況下直接調(diào)用成員函數(shù)地址,必須手工處理各種調(diào)整,沒(méi)有簡(jiǎn)單的統(tǒng)一方法。

 

posted on 2010-03-11 18:03 肥仔 閱讀(1385) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++ 基礎(chǔ)

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            制服丝袜亚洲播放| 亚洲国产日韩精品| 亚洲激情欧美| 99这里只有精品| 亚洲日本va午夜在线电影| 噜噜噜躁狠狠躁狠狠精品视频| 欧美一区二区三区视频在线观看| 国产精品亚洲不卡a| 欧美1区2区视频| 欧美日韩一区三区| 久久综合色播五月| 另类亚洲自拍| 亚洲国产岛国毛片在线| 夜色激情一区二区| 一区二区三区欧美激情| 欧美日一区二区三区在线观看国产免 | 午夜精品久久久久影视| 亚洲成色精品| 欧美精品激情blacked18| 欧美第一黄色网| 一区二区三区精品| 欧美www视频| 亚洲精品乱码视频| 久久爱www久久做| 在线视频日韩精品| 亚洲毛片av在线| 久久国产主播| 亚洲天堂免费观看| 久久资源在线| 另类专区欧美制服同性| 欧美激情综合亚洲一二区 | 免费不卡在线观看| 久久riav二区三区| 久久精品国产欧美激情| 欧美中文字幕不卡| 一区二区欧美在线观看| 国产精品久线观看视频| 国产一区二区三区四区老人| 亚洲一区二区3| 欧美激情一区二区三级高清视频| 在线亚洲激情| 欧美一区二区在线免费观看| 亚洲欧美激情诱惑| 欧美高清在线视频| 久久久.com| 欧美中文字幕第一页| 久久精品视频99| 麻豆国产精品777777在线| 国产精品看片你懂得| 狠狠色狠色综合曰曰| 久久在线视频在线| 亚洲欧洲一级| 亚洲一区二区网站| 亚洲精品美女免费| 久久综合给合久久狠狠狠97色69| 国产欧美日韩视频一区二区三区 | 久久夜色精品亚洲噜噜国产mv| 最新成人av在线| 久久人人超碰| 国产视频在线一区二区| 亚洲欧美日韩国产精品| 欧美一进一出视频| 在线视频日韩| 麻豆精品在线观看| 久久久一区二区三区| 国产精品―色哟哟| 99在线热播精品免费| avtt综合网| 欧美日韩二区三区| 亚洲激情综合| 99国产一区| 国产精品久久久久久久久久免费看| 亚洲国产天堂久久国产91| 亚洲人成精品久久久久| 美女网站久久| 99视频国产精品免费观看| 日韩视频中午一区| 欧美婷婷久久| 久久久久成人精品| 亚洲国产精品激情在线观看| 亚洲精品在线免费| 国产精品九色蝌蚪自拍| 亚洲欧美国产高清| 欧美成人嫩草网站| 亚洲男女自偷自拍| 国产一区二区高清视频| 欧美成ee人免费视频| 亚洲深夜av| 亚洲成人在线免费| 久久精品国产亚洲一区二区| 欧美专区第一页| 老鸭窝毛片一区二区三区| 亚洲国产视频直播| 国产精品欧美日韩一区| 久热精品视频在线观看一区| 亚洲精品久久7777| 久久久91精品国产一区二区精品| 91久久精品一区二区别| 国产欧美精品在线| 欧美日本视频在线| 另类综合日韩欧美亚洲| 亚洲欧美日本视频在线观看| 亚洲裸体俱乐部裸体舞表演av| 久久精品综合一区| 午夜亚洲影视| 午夜精品久久久久久久99黑人| 在线色欧美三级视频| 国产亚洲第一区| 国产免费观看久久黄| 国产精品二区影院| 欧美日韩一级视频| 国产精品高潮久久| 国产伦精品一区二区三| 国产精品午夜电影| 国产精品一区二区三区久久久| 国产精品久久久久久久一区探花| 欧美日韩激情小视频| 欧美日韩日日夜夜| 国产精品免费一区豆花| 国产精品久久久999| 国产伦精品一区二区三区在线观看 | 欧美高清在线观看| 国产精品美女主播| 亚洲免费观看高清在线观看| 99精品国产高清一区二区| 亚洲视频一二三| 男女激情久久| 国产伦精品一区二区三区照片91| 韩国自拍一区| 香蕉久久一区二区不卡无毒影院| 久久青青草原一区二区| 亚洲精品国产无天堂网2021| 亚洲欧美日韩国产| 欧美激情国产精品| 伊大人香蕉综合8在线视| 亚洲网站啪啪| 亚洲区免费影片| 免费一级欧美片在线播放| 国产一区二区欧美日韩| 亚洲一区中文| 日韩视频在线免费观看| 欧美高清视频在线观看| 在线免费观看日韩欧美| 久久久精品性| 久久精品91久久久久久再现| 国产精品视频久久久| 亚洲你懂的在线视频| 99视频在线精品国自产拍免费观看| 老司机精品视频一区二区三区| 国产一区二区无遮挡| 久久久久久一区二区三区| 亚洲欧美中文日韩在线| 国产揄拍国内精品对白| 欧美专区日韩专区| 欧美一区二区在线免费播放| 精品999网站| 亚洲国产中文字幕在线观看| 欧美精品日韩三级| 午夜免费电影一区在线观看| 欧美一区二区三区免费视| 一区二区在线观看视频在线观看| 麻豆国产va免费精品高清在线| 久久只有精品| 欧美一区三区二区在线观看| 久久久久一区二区三区| 中文在线资源观看网站视频免费不卡 | 欧美精品成人| 欧美在线网站| 欧美激情一区二区在线| 亚洲欧美电影在线观看| 午夜一区不卡| 99国产精品一区| 久久久www| 欧美在线一级va免费观看| 欧美寡妇偷汉性猛交| 久久久久久日产精品| 欧美日韩亚洲一区二区三区在线| 久久久精品国产免大香伊| 欧美日韩一区三区四区| 牛牛国产精品| 激情欧美一区二区三区| 一区二区欧美激情| 亚洲精品国偷自产在线99热| 先锋影音久久| 亚洲欧洲av一区二区| 欧美色123| 亚洲视频一区| 欧美一区二区免费观在线| 国产精品chinese| 一区二区三区欧美| 欧美一区二区三区视频免费播放| 欧美日韩国产高清视频| 亚洲精品免费网站| 亚洲欧美日韩中文视频| 国产精品国产三级国产aⅴ浪潮 | 欧美一区二区视频在线观看| 午夜精品剧场| 在线观看国产成人av片| 欧美成人免费播放| 亚洲一区欧美一区|