所謂多態,即“多種形態“。
C++中虛函數的主要作用就是實現多態,每一個具有虛函數的類都叫做多態類。這個虛函數或者是從基類繼承來的,或者是自己新增的。C++編譯器爲每一個多態類至少創
建一個虛函數表(vtable),他其實就是一個函數指針數組,其中存放着這個類所有的虛函數的地址及該類的類型信息,其中也包括那些繼承但未改寫的虛函數。簡單地說父類
的指針/引用調用重寫的虛函數,當父類指針/引用指向父類對象時調用的是父類的函數,指向子類對象時調用的是子類的函數。
【以下測試均在windows7 32位vs2008環境下的測試】
1、探索虛函數表
虛函數表是通過一塊連續內存來存儲虛函數的地址。這張表解決了繼承、虛函數(重寫)的問題。在虛函數的對象實例中都存在一張虛函數表、虛函數表就像一張地圖、指
明瞭實際應該調用的虛函數。
#include<iostream>
using namespace std;
class Base
{
public:
virtual void func1()
{ }
virtual void func2()
{ }
private:
int a;
};
void Test1()
{
Base b1;
}
int main()
{
Test1();
return 0;
}
【虛函數表】
2、探索單繼承對象模型
class Base
{
public:
virtual void func1()
{
cout<<"Base::func1"<<endl;
}
virtual void func2()
{
cout<<"Base::func2"<<endl;
}
private:
int a;
};
class Derive:public Base
{
public:
virtual void func1()
{
cout<<"Derve::func1"<<endl;
}
virtual void func3()
{
cout<<"Derve::func3"<<endl;
}
virtual void func4()
{
cout<<"Derve::func4"<<endl;
}
private:
int b;
};
typedef void(*FUNC)();
void PrintVTable(int *VTable)
{
cout<<"虛表地址->"<<VTable<<endl;
for(int i=0;VTable[i]!=0;++i)
{
printf("第%d個虛函數地址:0X%x,->",i,VTable[i]);
FUNC f=(FUNC) VTable[i];
f();
}
cout<<endl;
}
void Test1()
{
Base b1;
Derive d1;
int* VTable1=(int*)(*(int*)&b1);
int* VTable2=(int*)(*(int*)&d1);
PrintVTable(VTable1);
PrintVTable(VTable2);
}
VS2008監視窗口中的虛表
可以看到派生類Derive::func1重寫基類Base::func1,覆蓋了相應虛表位置上的函數。(可以看到這裏沒有看到派生類Derive中的func3和func4,這個函數就放在func2的後面,這
裏沒有顯示是vs的問題(bug))。
【單繼承對象模型】
3、探索多重繼承的內存分佈
class Base1
{
public:
virtual void func1()
{
cout<<"Base1::func1"<<endl;
}
virtual void func2()
{
cout<<"Base1::func2"<<endl;
}
private:
int b1;
};
class Base2
{
public:
virtual void func1()
{
cout<<"Base2::func1"<<endl;
}
virtual void func2()
{
cout<<"Base2::func2"<<endl;
}
private:
int b2;
};
class Derive:public Base1,public Base2
{
public:
virtual void fun1()
{
cout<<"Derive::func1"<<endl;
}
virtual void fun3()
{
cout<<"Derive::func3"<<endl;
}
private:
int d1;
};
typedef void(*FUNC)();
void PrintVTable(int *VTable)
{
cout<<"虛表地址->"<<VTable<<endl;
for(int i=0;VTable[i]!=0;++i)
{
printf("第%d個虛函數地址:0X%x,->",i,VTable[i]);
FUNC f=(FUNC) VTable[i];
f();
}
cout<<endl;
}
void Test1()
{
Derive d1;
int* VTable=(int*)(*(int*)&d1);
PrintVTable(VTable);
VTable=(int*)(*((int*)&d1+sizeof(Base1)/4));
PrintVTable(VTable);
}
【多重繼承對象模型】
4、多態
多態即多種形態,C++的多態分爲靜態多態和動態多態。
(1)靜態多態就是重載,因爲是在編譯期決議確定,所以稱爲靜態多態。
(2)動態多態就是通過繼承重寫基類的虛函數實現的多態,因爲是在運行時決議確定、所以稱爲動態多態。