→ remmurds:現在有支援多重繼承的語言大概只剩下C++ 建議你別把時間 02/11 20:11
→ remmurds:花太多在這上面 02/11 20:11
> -------------------------------------------------------------------------- <
作者: littleshan (我要加入劍道社!) 看板: C_and_CPP
標題: Re: [問題] 多重繼承疑惑
時間: Thu Feb 11 17:52:03 2010
※ 引述《QQ29 (我愛阿蓉)》之銘言:
: 有點走火入魔了....
: 現在試著了解一下多重繼承
: http://nopaste.csie.org/5f8d3
: 這是不使用虛擬繼承跑跑看的結果
: 發現new的 和 直接用物件 印出來的結果竟然有差異
: 先拿物件的方式印來看
: A::a 分給B::a 和C::a 因為D先繼承C 所以A::a和C::a是同一個變數
: 位址一樣...可以接受(這也是更改繼承順序得到的心得....)
: 但是我用new來看結果發現A::a 是一個 B::a和C::a竟然是一樣 很奇怪
咳咳...你用了錯誤的轉型。
先來看看你如何把 p 轉型成 B*:
cout<<&( ((B*)&p)->B::a )<<endl;
首先你用 &p 就錯了...&p 是 B**,也就是指向指標的指標,而不是指向 A 的指標。
因此至少你要改成:
cout<<&( ((B*)p)->B::a )<<endl;
不幸的是,這樣做的結果不如預期。你的想法可能是:
「p 的型別雖然是 A*,但它實際上指向 D 物件,我希望取出這個 D 物件中,
屬於 B 的那部份」
OK...現在,假設你是 compiler,你要怎麼知道「p 實際指向一個 D 物件」?
事實上是 compiler 根本無法知道 p 指向什麼,因為同樣的 code 我們可以這樣寫:
void print(A* p)
{
cout<<&( ((B*)p)->B::a )<<endl;
}
print(new A);
print(new B);
print(new C);
print(new D);
你注意到了嗎...compiler 根本就無法知道他接的 p 是來自於哪一種物件,
所以你寫 (B*)p,其實就只是把 p 的內容「直接」當成一個指向 B 的指標,
而不是「p 其實是個 D*,而 D 裡面有 B,所以應該取出 D 裡面的那份 B」,
compiler 不知道 p 真正指向什麼的。
如果上面的東西你能理解,我們繼續來看要怎麼解決這問題。
回想一下我上一篇提到 virtual function,想一下:
如果 a 這個東西並不是某個 member variable 而是 member function,
為什麼 compiler 會知道 p 的真正形別?
void print(A* p)
{
// 我不知道 p 指向什麼,但我可以從 vtable 中找出 function pointer
cout << p->a() << endl;
}
print(new A); // 使用 A::a()
print(new D); // 使用 D::a()
是的,答案就是利用 vtable。事實上 compiler 在 vtable 中,
除了加入 function pointer 之外,還會記錄這個 vtable 屬於哪個 class。
而 C++ 提供了 dynamic_cast 這個轉型用的 operator,幫助你在這種情況下轉形。
所以你的 code 要改成這樣:
A *p =(B*) new D;
cout << &(p->A::a) << endl;
cout << &( (dynamic_cast<B*>(p) )->B::a) << endl;
cout << &( (dynamic_cast<C*>(p) )->C::a) << endl;
dynamic_cast<B*>(p) 的意思是說,我不知道 p 真正指向哪一種 class,
但我想利用 vtable 中的資訊,試圖把 p 「正確地」轉成 B*。
改用 dynamic_cast 後,我想結果應該會符合你的預期。
: 於是我把C和B class都加上virtual public: http://nopaste.csie.org/3e47e
: 物件的方式印出 全部都一樣 恩~可以接受
: 但是用new的方式印
: 奇怪A::a 又和其他不一樣了?
: 是我cout寫錯嗎 new的和用物件的方式怎麼會有差異
: 請教一下
: 謝謝
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.29.108
推 QQ29:..................我太誇張了 &p .....我瞎了!!!! 02/11 18:57
→ QQ29:謝謝l大 有許多東西可以補強我的觀念 謝謝你 02/11 19:08
→ sbrhsieh:要使用 RTTI(dynamic_cast) 必須得是 polymorphic type 02/11 20:42
→ sbrhsieh:polymorphic type: class 要有 virtual function(vtable) 02/11 20:43
推 nowar100:天阿!為什麼強者這麼多! m不完啦 XD 02/11 20:49
> -------------------------------------------------------------------------- <
作者: sbrhsieh (偶爾想擺爛一下) 看板: C_and_CPP
標題: Re: [問題] 多重繼承疑惑
時間: Thu Feb 11 20:38:27 2010
※ 引述《littleshan (我要加入劍道社!)》之銘言:
: 是的,答案就是利用 vtable。事實上 compiler 在 vtable 中,
: 除了加入 function pointer 之外,還會記錄這個 vtable 屬於哪個 class。
: 而 C++ 提供了 dynamic_cast 這個轉型用的 operator,幫助你在這種情況下轉形。
: 所以你的 code 要改成這樣:
: A *p =(B*) new D;
: cout << &(p->A::a) << endl;
: cout << &( (dynamic_cast<B*>(p) )->B::a) << endl;
: cout << &( (dynamic_cast<C*>(p) )->C::a) << endl;
: dynamic_cast<B*>(p) 的意思是說,我不知道 p 真正指向哪一種 class,
: 但我想利用 vtable 中的資訊,試圖把 p 「正確地」轉成 B*。
: 改用 dynamic_cast 後,我想結果應該會符合你的預期。
另外也可以考慮使用 static_cast 來偏移 D* pointer。
D *p = new D;
cout << &static_cast<B*>(p)->a << endl;
cout << &static_cast<C*>(p)->a << endl;
cout << "D object:" << p << endl;
cout << "B object in D:" << static_cast<B*>(p) << endl;
cout << "C object in D:" << static_cast<D*>(p) << endl;
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 218.173.136.12