虛基類/抽象類
抽象類:有純虛函式的類
虛繼承
通過修飾繼承方式, 如代碼2是虛繼承,被虛繼承的類稱為虛基類
虛繼承派生類的記憶體布局方式
先是vbptr => 派生類的資料 =>基類的資料 ,
對比代碼1和代碼2,發現原本基類資料在前面,派生類資料在后面,但是在虛繼承的時候
基類資料方式放到了后面,前面放了vbptr和派生類資料.
vbprt指向的是vbtable ,vbtable中存盤的資料是偏移量, 是vbptr指標起始位置到基類的偏移量,見代碼2和代碼2后面的圖片
通過偏移量可以找到基類資料,仔細對比代碼1和代碼2
vfprt/vbptr
vftabe/vbtable
代碼1
class A{
public:
int ma;
protcted:
int mb;
private:
int mc;
}
//B繼承 A,
class B : public A{
public:
int md;
potected:
int me;
private:
int mf;
}


代碼2 虛繼承
#include <iostream>
using namespace std;
class A{
public:
int ma;
protected:
int mb;
private:
int mc;
};
//B繼承 A,
class B : virtual public A{
public:
int md;
protected:
int me;
private:
int mf;
};
int main(){
return 0;
}

代碼3
#include <iostream>
using namespace std;
class A{
public:
int ma;
virtual void show()
{
}
protected:
int mb;
private:
int mc;
};
//B繼承 A,
class B : public A{
public:
int md;
virtual void show()
{
}
protected:
int me;
private:
int mf;
};
int main(){
A *PA=new B();
PA->show();
return 0;
}

代碼4
#include <iostream>
using namespace std;
class A{
public:
int ma;
virtual void show()
{
}
protected:
int mb;
private:
int mc;
};
//B繼承 A,
class B : virtual public A{
public:
int md;
virtual void show()
{
}
protected:
int me;
private:
int mf;
};
int main(){
A *PA=new B();
PA->show(); // 能正常呼叫B的show() 方法
delete PA; // 運行報錯! 如下圖
return 0;
}
vfptr/vbptr vbtable/vbtable 同時出現
當一個類有虛函式,那么就會生成vfptr,vfptr指向vftable,vftable中主要包含RTTI資訊和虛函式地址資訊
vbptr 專門為派生類從基類中虛繼承用得,vbptr指向vbtable,vbtable中主要存盤了vbptr到虛基類地址的偏移量

運行報錯原因

PA->show();//正常
delete PA ;//運行報錯
A *PA=new B(); 用基類指標指向派生類,問題:new B()回傳的地址是vbptr起始地址?還是基類vfptr的起始地址?
基類指標指向派生類物件,PA指向的是基類的起始地址,即上圖中vfptr起始地址,PA->show()能正常呼叫,因為
PA指向vfptr起始地址,直接可以將vfptr讀取出來,但是釋放記憶體的時候應該從vbptr地址開始釋放,所以報錯.
代碼5
#include <iostream>
using namespace std;
class A {
public:
int ma;
void operator delete(void *p) {
cout <<"A Operator Delete "<< p << endl;
free(p);
}
virtual void show()
{
}
protected:
int mb;
private:
int mc;
};
//B繼承 A,
class B : virtual public A {
public:
int md;
void * operator new(size_t size) {
void * p = malloc(size);
cout << "class B operator new malloc Address=" << p << endl;
return p;
}
virtual void show()
{
}
protected:
int me;
private:
int mf;
};
int main() {
A *PA = new B();
cout << PA << endl;
delete PA;
system("pause");
return 0;
}


結合代碼5中申請的記憶體地址,和回傳的地址,類的記憶體結構,偏移量,等資訊進行分析了解
如果代碼5中改成如下
int main() {
B b;
A *PA = &b;
system("pause");
return 0;
}
b在堆疊上申請空間就不會有上面釋放記憶體的錯誤(windows vc編譯環境 ).
另外vfptr 是歸屬 基類還是派生類問題?
如果基類本身有虛函式的,那么vfptr歸屬基類,如果基類中沒有虛函式,派生類有虛函式,那么vfptr歸屬派生類 如下圖

vbtable中的偏移量是vbptr的起始地址到基類的偏移量
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538692.html
標籤:其他
上一篇:不好意思,UUID 該換了!
下一篇:Kafka基本概念大全
