C++程式運行時記憶體布局之———-this到底是什嗎?

來源:互聯網
上載者:User

原文地址:http://blog.csdn.net/smstong/article/details/6604388

 

先問一個問題,在C++裡,成員函數裡的this指標和調用此函數的對象地址總是一樣的嗎?如果你的回答是:不一定。那麼至少你是個老手吧,下面的內容你就不用看了;如果你的回答是:是啊,那麼強烈建議你看看下面的內容。

 

非靜態成員函數,無論是不是虛函數,都隱藏了一個this指標參數。這個參數的目的就是給函數提供一個基地址,以便於函數體內能找到對象的成員變數。那非靜態成員函數是如何根據this指標找到成員變數的呢?直接看例子吧

 

1沒有虛表的情況

  1. #include <iostream>   
  2. #include <stdio.h>   
  3.   
  4. using namespace std;  
  5.   
  6. class A  
  7. {  
  8. public:  
  9.     int x;  
  10.     int y;  
  11. public:  
  12.     void F1()  
  13.     {  
  14.         this->x = 1;  
  15.         this->y = 2;  
  16.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  17.     }  
  18. };  
  19.   
  20.   
  21.   
  22. int main(int argc, char** argv)  
  23. {  
  24.     A a;  
  25.     cout<<"a對象的地址是:"<<&a<<endl;  
  26.     cout<<"a對象的大小是:"<<sizeof(A)<<endl;  
  27.     cout<<"成員a.x的地址是: "<<&a.x<<endl;  
  28.     cout<<"成員a.x的位移是:"<<&A::x<<endl;  
  29.     a.F1();  
  30.     cin>>argc;  
  31.     return 0;  
  32. }  

那麼函數F1的實現虛擬碼為:

 

*(this+&A::x-1) = 1;

*(this+&A::y-1) = 2;

 

其中&A::x是成員x的位移+1,&A::y是成員y的位移+1,這可是C++基本文法的知識,希望你知道,呵呵。可這些位移量是相對應那裡的位移呢,是對象地址嗎,答案是NO。是相對於第一個成員變數的位移,這對於有些對象也許沒有差別,但是對於有虛表的類的對象,就有差別了。這些位移在編譯期間就是確定了的。對於本例在VC++2010下&A::x,值為1, &A::y,值為5。為什麼不是0,4,請看《Inside The C++ Object Model》。

所以,對於找到成員變數,需要進一步確定的只有this的值。程式運行結果如下:

可見此例中,對象的地址與this指標的地址相同,記憶體配置圖如下所示。

2有一個虛表的情況

  1. #include <iostream>   
  2. #include <stdio.h>   
  3.   
  4. using namespace std;  
  5.   
  6. class A  
  7. {  
  8. public:  
  9.     int x;  
  10.     int y;  
  11. public:  
  12.     virtual void F1()  
  13.     {  
  14.         this->x = 1;  
  15.         this->y = 2;  
  16.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  17.     }  
  18. };  
  19.   
  20.   
  21.   
  22. int main(int argc, char** argv)  
  23. {  
  24.     A* p = new A();  
  25.     cout<<"a對象的地址是:"<<p<<endl;  
  26.     cout<<"a對象的大小是:"<<sizeof(A)<<endl;  
  27.     cout<<"成員a.x的地址是: "<<&p->x<<endl;  
  28.     cout<<"成員a.x的位移是:"<<&A::x<<endl;  
  29.     p->F1();  
  30.     cin>>argc;  
  31.     return 0;  
  32. }  

 

此時函數F1的實現虛擬碼為:

 

*(this+4+&A::x-1) = 1;  //+4是因為存在虛表指標

*(this+4+&A::y-1) = 2;  //+4是因為存在虛表指標

 

程式運行結果如下:

記憶體布局如下:

結論:this的值和對象地址相同,成員變數位移量不因虛表指標存在而改變。帶虛表的類的成員函數對成員變數的定址方式不同,增加一個+4。

3單繼承的情況

  1. #include <iostream>   
  2. #include <stdio.h>   
  3.   
  4. using namespace std;  
  5.   
  6. class A  
  7. {  
  8. public:  
  9.     int x;  
  10.     int y;  
  11. public:  
  12.     void F1()  
  13.     {  
  14.         this->x = 1;  
  15.         this->y = 2;  
  16.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  17.     }  
  18. };  
  19.   
  20. class B : public A  
  21. {  
  22. public:  
  23.     int z;  
  24. public:  
  25.     virtual void F2()  
  26.     {  
  27.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  28.     }  
  29. };  
  30.   
  31. int main(int argc, char** argv)  
  32. {  
  33.     B* pb = new B();  
  34.     cout<<"對象的地址為:"<<std::hex<<std::showbase<<pb<<endl;  
  35.     pb->F1();  
  36.     pb->F2();  
  37.   
  38.     cin>>argc;  
  39.     return 0;  
  40. }  

 

運行結果:

記憶體布局:

結論:this指標的值受兩個因素確定,一是對象的地址,二是定義成員函數的類。This指向的是對象內,定義該方法的類得subobject。

4 多繼承的情況

先看A沒有虛函數,B有虛函數的情況

  1. #include <iostream>   
  2. #include <stdio.h>   
  3.   
  4. using namespace std;  
  5.   
  6. class A  
  7. {  
  8. public:  
  9.     int x;  
  10.     int y;  
  11. public:  
  12.     void F1()  
  13.     {  
  14.         this->x = 1;  
  15.         this->y = 2;  
  16.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  17.     }  
  18. };  
  19.   
  20. class B  
  21. {  
  22. public:  
  23.     int z;  
  24. public:  
  25.     virtual void F2()  
  26.     {  
  27.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  28.     }  
  29. };  
  30.   
  31. class C : public A, public B  
  32. {  
  33. public:  
  34.     int a;  
  35. public:  
  36.     virtual void F2()  
  37.     {  
  38.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  39.     }  
  40.     void F3()  
  41.     {  
  42.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  43.     }  
  44. };  
  45. int main(int argc, char** argv)  
  46. {  
  47.     C* pc = new C();  
  48.     cout<<"對象的大小為:"<<sizeof(C)<<endl;  
  49.     cout<<"對象的地址為:"<<std::hex<<std::showbase<<pc<<endl;  
  50.     pc->F1();  
  51.     pc->F2();  
  52.     pc->F3();  
  53.   
  54.     cin>>argc;  
  55.     return 0;  
  56. }  

結果:

記憶體布局:

再看,如果A,B都有虛函數的情況。

代碼:

  1. #include <iostream>   
  2. #include <stdio.h>   
  3.   
  4. using namespace std;  
  5.   
  6. class A  
  7. {  
  8. public:  
  9.     int x;  
  10.     int y;  
  11. public:  
  12.     virtual void F1()  
  13.     {  
  14.         this->x = 1;  
  15.         this->y = 2;  
  16.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  17.     }  
  18. };  
  19.   
  20. class B  
  21. {  
  22. public:  
  23.     int z;  
  24. public:  
  25.     virtual void F2()  
  26.     {  
  27.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  28.     }  
  29. };  
  30.   
  31. class C : public A, public B  
  32. {  
  33. public:  
  34.     int a;  
  35. public:  
  36.     virtual void F2()  
  37.     {  
  38.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  39.     }  
  40.     void F3()  
  41.     {  
  42.         cout<<"this指標得值是:"<<std::hex<<std::showbase<<this<<endl;  
  43.     }  
  44. };  
  45. int main(int argc, char** argv)  
  46. {  
  47.     C* pc = new C();  
  48.     cout<<"對象的大小為:"<<sizeof(C)<<endl;  
  49.     cout<<"對象的地址為:"<<std::hex<<std::showbase<<pc<<endl;  
  50.     cout<<"x的地址"<<&pc->x<<endl;  
  51.     cout<<"z的地址"<<&pc->z<<endl;  
  52.     pc->F1();  
  53.     pc->F2();  
  54.     pc->B::F2();  
  55.     pc->F3();  
  56.   
  57.     cin>>argc;  
  58.     return 0;  
  59. }  

結果:

記憶體布局:

結論:再一次驗證了this指標的值的確定方法,this始終要保證指向定義了該成員函數的類得subobject。因為C++保證base class subobject與base class object完全對應,從而保證了成員函數能根據成員變數在定義了該變數的類中的位移定址。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.