非虛擬繼承
ide
【帶虛函數的類】函數
class Baseui
{spa
public:對象
virtual void FunTest1()blog
{繼承
cout<<"Base::FunTest1()"<<endl;get
}編譯器
virtual void FunTest2()it
{
cout<<"Base::FunTest2()"<<endl;
}
int _data1;
};
int main()
{
Base b;
b._data1 = 0x01;
return 0;
}
Base類沒有顯式定義本身的構造函數,此時編譯器會和成默認的構造函數,
合成的構造函數中主要完成在對象頭4個字節中填寫虛表地址:
Base類對象最後的模型以下:
注意:同一個類的對象共用同一個虛表
從上述的結果中能夠獲得印證。
【單繼承(派生類中沒有虛函數覆蓋)】
class Base
{
public:
virtual void FunTest1()
{cout<<"Base::FunTest1()"<<endl;}
virtual void FunTest2()
{cout<<"Base::FunTest2()"<<endl;}
int _data1;
};
class Derive:public Base
{
public:
virtual void FunTest3()
{cout<<"Derive::FunTest3()"<<endl;}
virtual void FunTest4()
{cout<<"Derive::FunTest4()"<<endl;}
int _data2;
};
// 打印虛表
typedef void (*VtbFun)();
void PrintVtable()
{
cout<<"Derive類的虛函數表:"<<endl;
Derive d1;
d1._data1 = 0x01;
d1._data2 = 0x02;
int* pVTable = (int*)*(int*)&d1;
VtbFun FunTest = (VtbFun)*pVTable;
while(NULL != FunTest)
{
FunTest();
cout<<(int*)FunTest<<endl;
pVTable += 1;
FunTest = (VtbFun)*pVTable;
}
cout<<"虛表結束:"<<endl;
}
int main()
{
Base b1;
Derive d1;
return 0;
}
按照如上分析的順序,探索下單繼承下派生類對象模型以及虛表
首先看看編譯器爲派生類合成的缺省構造函數:
派生類構造函數中進行了以下事情:
Derive d1;
d1._data1 = 0x01;
d1._data2 = 0x02;
派生類最後的對象模型爲:
【單繼承(派生類中有虛函數覆蓋)】
class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
int _data1;
};
class Derive:public Base
{
public:
virtual void FunTest1()
{
cout<<"Derive::FunTest1()"<<endl;
}
virtual void FunTest3()
{
cout<<"Derive::FunTest3()"<<endl;
}
virtual void FunTest4()
{
cout<<"Derive::FunTest4()"<<endl;
}
int _data2;
};
int main()
{
PrintVtable();
return 0;
}
派生類對象模型及虛表建議規則:
【多繼承(派生類不覆蓋基類虛函數)】
class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
int _data1;
};
class Base1
{
public:
virtual void FunTest3()
{
cout<<"Base1::FunTest3()"<<endl;
}
virtual void FunTest4()
{
cout<<"Base1::FunTest4()"<<endl;
}
int _data2;
};
class Derive:public Base, public Base1
{
public:
virtual void FunTest5()
{
cout<<"Derive::FunTest5()"<<endl;
}
int _data3;
};
int main()
{
cout<<"sizeof(Derive) = "<<sizeof(Derive)<<endl;
Derive d;
d._data1 = 0x01;
d._data2 = 0x02;
d._data3 = 0x03;
PrintVtable();
return 0;
}
一樣:看看編譯器合成的派生類的對象作了什麼工做
觀察下派生類的對象模型和虛表的創建過程
從上面的結果能夠看出,Derive類本身特有的虛函數直接添加在Base類對應虛函數表最後的位置,你們可將Base和Base1的順序交換驗證下。
【多繼承(派生類覆蓋基類虛函數)】
class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
int _data1;
};
class Base1
{
public:
virtual void FunTest3()
{
cout<<"Base1::FunTest3()"<<endl;
}
virtual void FunTest4()
{
cout<<"Base1::FunTest4()"<<endl;
}
int _data2;
};
// 此次將繼承列表中Base和Base1的位置互換
class Derive:public Base1, public Base
{
public:
virtual void FunTest1()
{
cout<<"Derive::FunTest1()"<<endl;
}
virtual void FunTest3()
{
cout<<"Derive::FunTest3()"<<endl;
}
virtual void FunTest5()
{
cout<<"Derive::FunTest5()"<<endl;
}
int _data3;
};
int main()
{
PrintVtable();
return 0;
}
此時派生類的對象模型和虛表的結構:
虛擬繼承
// 沒有虛函數覆蓋,但派生類有本身的虛函數
class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
int _data1;
};
class Derive:virtual public Base
{
public:
virtual void FunTest3()
{
cout<<"Derive::FunTest3()"<<endl;
}
virtual void FunTest4()
{
cout<<"Derive::FunTest4()"<<endl;
}
int _data2;
};
虛擬繼承編譯器爲派生類合成的默認構造函數分析
編譯器爲派生類合成的默認構造函數任務分析:
虛擬繼承派生類對象模型分析