倒立平行四邊形的虛擬繼承解析_及對com/dll的影響討論

來源:互聯網
上載者:User

倒立平行四邊形的虛擬繼承解析
結構:
                A
            |        |
    virtual      virtual
          |           |
          D           D2
             |      |
                TF

#include <iostream>

using namespace std;

class A
{
public:
 A(int i=-1)
 {
  this->m_a = i;
 }
 virtual void fa()
 {
  cout<<"a::fa/n";
  return ;
 }
 virtual void fa2()
 {
  cout<<"a::fa2/n";
 }
 virtual void fa3()
 {
  cout<<"a::fa3/n";
 }
 virtual void fa4()
 {
  cout<<"a::fa4/n";
 }
protected:
 int m_a;
};

class D:  virtual public A  //virtual
{
public:
 virtual void fa()
 {
  cout<<"d::fa/n";
 }
 virtual void fa3()
 {
  cout<<"d::fa3/n";
 }
 virtual void fa4()
 {
  cout<<"d::fa4/n";
 }
 virtual void fd2()
 {
  cout<<"d::fd2/n";
 }
 virtual void fd3()
 {
  cout<<"d::fd3/n";
 }
 D(int a=1,int d=100):A(1)
 {
  this->m_d = 100;
 }
protected:
 int m_d;
};

class D2: virtual public A// virtual
{
public:
 virtual void fa2()
 {
  cout<<"D2::fa2/n";
 }
/* virtual void fa3()
 {
  cout<<"d2::fa3/n";
 }
//如果D ,D2都給出實現,但是TF不給出fa3的實現的話就會編譯出錯,
*/
 virtual void fa4()
 {
  cout<<"d2::fa4/n";
 }
 virtual void fd22()
 {
   cout<<"d2::fdd22/n";
 }
 D2(int a=2,int dd2=200):A(2)
 {
  this->m_dd2=200;
 }
protected:
 int m_dd2;
};
class TF:public D,public D2
{
public:
 virtual void ftf()
 {
  cout<<"d2::fdd22/n";
 }
 virtual void ftf2()
 {
  cout<<"d2::fdd22/n";
 }
 virtual void fa4()//最高優先順序
 {
  cout<<"tf::fa4/n";
 }
 TF():D(),D2()
 {
  m_tf=300;
 }
protected:
 int m_tf;
};

當建立TF的對象時建構函式的執行順序是:
TF()函數頭-------〉完全執行A(),注意在執行這個函數時,調用的時無參的建構函式,或者是有預設值的建構函式,因為這是規則,在這種情形下,假定編譯器不這麼做,那麼他使用的參數應該是D的建構函式還是D2的建構函式的參數呢? 所以,他就什麼都不選。就使用無參建構函式,或有預設值的建構函式。
-------〉完全執行D(),
-------〉完全執行D2(),
------->TF()函數體。

TF對象的記憶體空間可以分為三部分:D部分,D2部分,TF本特有的部分,其中
D部分分為: A部分,D特有的部分
D2部分分未:A部分,D2特有的部分
但是D,D2 部分中的A部分是相同的(使用相同的記憶體快)。
//至於具體的記憶體布局方式我不清楚是怎麼處理(放置)A這個共同快的
//不過呢可以猜測應該是D,D2 中至少有一個是使用索引或者指標指向了這個塊
//如果是只有一個使用索引(指標)那麼可以斷定這個記憶體在另外一個裡面
//如果兩個都使用索引(指標)那麼可以斷定可能是在 TF對象的開頭或者結尾放置了這個記憶體塊

/*根據這種布局方式,你可以判斷在顯事使用dll時,dll將不能使用這種繼承方式,否則在 用戶端將無法訪問。當然如果你告訴用戶端的你的類(組件)的布局方式,那麼就可以用這種方式了。
但是在com中這種方式是不被允許的,因為你不會告訴用戶端你的組件的聲明(布局)方式,你只會告訴用戶端你的介面的布局(聲明)方式。
*/
/*很遺憾,上面的那一段討論是錯誤的,在C++的com中可以這麼做,但是由於com規定語言無關性,同時別的
語言沒有虛擬繼承這種概念,所以將無法在別的語言中實現,所以com不建議使用虛擬繼承。況且在com是沒有必要進行介面的多重繼承的。理由是 你可以把把介面的虛擬繼承拆分成不用虛擬繼承的方式。
*/
這裡有一個關鍵的問題 那就是A部分是怎麼構建的,或者說用什麼方法來決定這個部分的值。在vc下,根據我
觀察得到的原則是:
A的非待用資料成員的值由A無參建構函式,或有預設值的建構函式中的操作決定。在上面的例子中m_a=-1
至於A有四個虛成員函數,對應的vtable中的三項的值的確定方式如下:
最先這個四個項的值就是A的四個虛函數的地址值。
然後再執行D()時如果D重寫了A的虛函數則相應的項的值由D的重寫虛函數的地址值來確定,(fa)
然後再執行D2()時如果D2重寫了A的虛函數則相應的項的值由D2的重寫虛函數的地址值來確定,(fa2)
注意這裡就會出現一個問題也就是如果D,D2 都重寫了一個函數,但是這個函數沒有被TF重寫,那麼就會發生變異錯誤。告訴你存在模糊現象。(fa3)
最後在執行TF()函數體時,如果TF重寫了A的虛函數則相應的項由TF的重寫的虛函數的地址來確定。也就是TF擁有最高的優先順序!!(比如fa4) 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.