多型的一個特殊例子
我們先回復一下多型,看下面一個例子
#include "stdafx.h"
class A1
{
public:
virtual void sample(int a,int b)=0;
};
class B1 :public A1
{
public:
virtual void sample (int a,int b){trace(“class B1:: sample”);};
};
class C1:public A1
{
public:
virtual void sample (int a,int b){ trace(“class C1:: sample”);};
};
int main(int argc, char* argv[])
{
A1 a1,a2;
B1 b1
C1 c1;
a1=&b1;
a2=&b2;
/////////////////////////////////////////////////
a1->sample(2,3);
a2->sample(1,3);
//////////////////////////////////////////////
return 0;
}
根據多型的特性a1->sample(2,3)呼叫的實際上是class B1:: sample
a2->sample(2,3)呼叫的實際上是class C1:: sample
這是一個最經典的多型的例子了,這裡我們不做過多解釋!
自以為對多型有了很深的瞭解,但是下面這個例子起初使我一頭霧水,”自高”的心態也就瓦解了,但總算功夫不負有心頭人,總算搞清楚原因了,先看看這個例子!
#include "stdafx.h"
class A1
{
public:
virtual void sample(int a,int b){};
};
class B1
{
public:
virtual void sample1(int a,int b){};
virtual void sample2(int a,int b){};
virtual void sample3(int a,int b){};
};
class C1:public A1,public B1
{
public:
virtual void sample2(int a,int b){};
virtual void sample1(int a,int b){};
virtual void sample(int a,int b){};
void setA1(void** a){*a=(A1*)this; }
void setB1(void** b){*b=(B1*)this; }
};
int main(int argc, char* argv[])
{
A1 *a1,*b2;
C1 c1;
c1.setA1((void**)&a1);
c1.setB1((void**)&b2);
a1->sample(2,3);
b2->sample(1,3);
return 0;
}
按照經典的例子看a1->sample(2,3); b2->sample(1,3);這個兩個呼叫的應該都是class C1:: sample(),令人遺憾的是a1->sample(2,3)是我們所希望看到的呼叫class C1:: sample(),而b2->sample(1,3);呼叫的卻是class C1:: sample1(),這是為什麼那!
下面就是我跟蹤DEBUG看到的結果
根據上圖!原因也就一幕瞭然了!
呼叫c1.setA1((void**)&a1);的時候,因為類CA1的原結構中虛擬函式表中就一項,這時候通過
*a=(A1*)this;的賦值過程,使得CA1的指標a1指向的就是c1中子物件A1虛擬函式表中的c1::sample(int,int).
呼叫c1.setB1((void**)&b1);的時候,因為類CA1的原結構中虛擬函式表中就一項,這時候通過
*a=(B1*)this;的賦值過程, 使得CA1的指標b1指向的就是c1中子物件B1虛擬函式表中第一項c1::sample1(int,int),其它的表項也就同時被切割掉了,這就解釋了為什麼b2->sample(1,3)為什麼會轉到c1::sample1(int,int)的不解了!也就是說這種情況下的賦值只有c1中子物件B1虛擬函式表中的第一項才被複制給b1指標!!