1. 程式人生 > >多型的一個特殊例子

多型的一個特殊例子

我們先回復一下多型,看下面一個例子
#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指標!!