單一繼承資料成員布局this指針偏移知識補充
this指針,加上偏移值 就的能夠通路對應的成員變量,比如m_bi = this指針+偏移值
#include <iostream>
using namespace std;
class Base
{
public:
int m_bi;
Base()
{
printf("Base::Base()的this指針是:%p!\n", this);//列印父類this指針
};
};
class MYACLS :public Base
{
public:
int m_i;
int m_j;
virtual void myvirfunc() {} //虛函數
MYACLS()
{
printf("MYACLS::MYACLS()的this指針是:%p!\n", this);//列印子類this指針
}
~MYACLS()
{
}
};
int main()
{
cout << sizeof(MYACLS) << endl;//24
//偏移值(相對父類或者子類this指針的)
printf("MYACLS::m_bi = %d\n", &MYACLS::m_bi);//0
printf("MYACLS::m_i = %d\n", &MYACLS::m_i);//12
printf("MYACLS::m_j = %d\n", &MYACLS::m_j);//16
MYACLS obj;
/*
Base::Base()的this指針是:0000006F4AEFFA40!
MYACLS::MYACLS()的this指針是:0000006F4AEFFA38!
this指針差了8位元組,差的是個vptr
*/
return 1;
}
多重繼承且父類都帶虛函數的資料成員布局
#include <iostream>
using namespace std;
class Base1
{
public:
int m_bi;
virtual void mybvirfunc() {}
Base1()
{
printf("Base1::Base1()的this指針是:%p!\n", this);
}
};
class Base2
{
public:
int m_b2i;
virtual void mybvirfunc2() {}
Base2()
{
printf("Base2::Base2()的this指針是:%p!\n", this);
}
};
class MYACLS :public Base1, public Base2
{
public:
int m_i;
int m_j;
virtual void myvirfunc() {} //虛函數
MYACLS()
{
int abc = 1; //友善加斷點
printf("MYACLS::MYACLS()的this指針是:%p!\n", this);
}
~MYACLS()
{
int def = 0;//友善加斷點
}
};
int main()
{
//二:多重繼承且父類都帶虛函數的資料成員布局
//(1)通過this指針列印,我們看到通路Base1成員不用跳 ,通路Base2成員要this指針要偏移(跳過)16位元組;
//(2)我們看到偏移值,m_bi和m_b2i偏移都是8;
//(3)this指針,加上偏移值 就的能夠通路對應的成員變量,比如m_b2i = this指針+偏移值
//我們學習得到一個結論:
//我們要通路一個類對象中的成員,成員的定位是通過:this指針(編譯器會自動調整)以及該成員的偏移值,這兩個因素來定義;
//這種this指針偏移的調整 都需要編譯器介入來處理完成;
cout << sizeof(MYACLS) << endl;//40
printf("MYACLS::m_bi = %d\n", &MYACLS::m_bi);//8
printf("MYACLS::m_b2i = %d\n", &MYACLS::m_b2i);//8
printf("MYACLS::m_i = %d\n", &MYACLS::m_i);//32
printf("MYACLS::m_j = %d\n", &MYACLS::m_j);//36
MYACLS myobj;
myobj.m_i = 3;
myobj.m_j = 6;
myobj.m_bi = 9;
myobj.m_b2i = 12;
/*
Base1::Base1()的this指針是:00000038C818F468!
Base2::Base2()的this指針是:00000038C818F478!
MYACLS::MYACLS()的this指針是:00000038C818F468!
*/
return 1;
}
左到右:
子類對象位址(紅色)
Base1繼承來的vptr,補齊,m_bi(藍色)
Base2繼承來的vptr, m_b21, 補齊(黃色)
子類自己的m_i和m_j(紅色)
編譯器角度
父類指針指向子類對象時,this指針偏移問題
int main()
{
//cout << sizeof(MYACLS) << endl;//40
//printf("MYACLS::m_bi = %d\n", &MYACLS::m_bi);//8
//printf("MYACLS::m_b2i = %d\n", &MYACLS::m_b2i);//8
//printf("MYACLS::m_i = %d\n", &MYACLS::m_i);//32
//printf("MYACLS::m_j = %d\n", &MYACLS::m_j);//36
MYACLS myobj;
Base2 *pbase2 = &myobj; //this指針調整導緻pbase2實際是向前走16個位元組的記憶體位置的
//站在編譯器視角,把上邊這行語句進行了調整
//Base2 *pbase2 = (Base2 *)(((char *)&myobj) + sizeof(Base1));
Base1 *pbase1 = &myobj; //不用調整this指針
Base2 *pbase3 = new MYACLS(); //父類指針指向new的子類對象 ,這裡new出來的是40位元組
MYACLS *psubobj = (MYACLS *)pbase3; //比上邊位址小了16位元組(偏移)
//delete pbase3; //報異常。是以我們認為pbase2裡邊傳回的位址不是配置設定的首位址,而是偏移後位址。
// //而真正配置設定的首位址應該是在psubobj裡邊的這個位址
delete psubobj;
return 1;
}