貌似有些同學還不太明白這個,我試著用c代碼描述c++類相關的一些實現方式。
設類abc,bc繼承於a,都有個虛函數f(),解構函式為虛
c++代碼
//---------A
struct a{
a(){
}
void f(){
printf("class a\n";
}
virtual ~a(){
}
};
struct b:public a{
b(){
}
virtual void f(){
printf("class b\n";
}
virtual ~b(){
}
};
struct c:public a{
c(){
}
void f(){
printf("class b\n";
}
virtual ~c(){
}
};
main(){
a* p=new a;
p->f();
delte p;
p=new b;
p->f();
delete p;
}
//C語言描述,文法問題請無視,否則要寫一大堆typedef定義類型
設c_a()為a建構函式 d_a()為a的解構函式,vt_a為a的虛函數表結構
b,c類似
先構造結構
struct vt_a{
destructFun_ptr;
virtual_f_ptr;
};
這裡b和c的vtable和a結構一致,沒有擴充函數
vt_b{
vt_a father;//
//擴充的其他函數在下面
};
struct a{
vt_a vtable;
//a的其他成員變數
...
};
struct b{
a father_a;
//b的其他成員變數
};
c和b類似
//產生虛函數表
vt_a vtable_a={
d_a,vf_a_f;
};
vt_b vtable_b={
d_b,vf_b_f;
};
vt_c vtable_c={
d_c,vf_c_f;
};
編譯
p=new a;
p->f();
delete p;
編譯為
//第一句
p=new_op(sizeof(a));//對應的new函數(全域,局部),可以認為就是malloc
a* pa==(a*)p;
pa->vtable=vtable_a; //對不同的子類,vtable指向不同的表
pa->c_a(pa);
//第二句
pa->vtable->virtual_f_ptr(pa);//這裡就是多態的實現方法(vtable的不同,實現調用子類的虛函數)
//第3句
pa->vtable->destructFun_ptr(pa);
delete_op(pa);//對應的delete函數,可以認為就是free
///最後是鏈式析構的實現方式
d_a(){
//自訂的代碼
...
}
d_b()
{
//自訂的代碼
...
//編譯器添加
d_a(this);
}
這就是鏈式析構的原理
編譯時間一個類的父類是一定可以確定的,可以這麼認為,一個子類的解構函式調用後,this就退化為父類的類型了,這時繼續調用父類的解構函式(編譯器實現),直到沒有父類為止。
多重繼承時情況和單繼承類似,只是記憶體布局不同,子類和父類指標轉換時可能會有位移值。