2012-09-20 66 views
9

任何人都可以解釋以下代碼的行爲嗎?地址,reinterpret_cast和多繼承

  1. 爲什麼我們必須在第一種情況下b = 3,即b2 == &d是真的嗎?
  2. 爲什麼在案例2中可以嗎?我已經打印了地址b2d,它們是不同的。
#include <iostream> 

using namespace std; 

class A 
{ 
public: 
    A() : m_i(0) { } 

protected: 
    int m_i; 
}; 

class B 
{ 
public: 
    B() : m_d(0.0) { } 

protected: 
    double m_d; 
}; 

class C 
    : public A 
    , public B 
{ 
public: 
    C() : m_c('a') { } 

private: 
    char m_c; 
}; 

int main() 
{ 
    C d; 
    B *b2 = &d; 

    cout << &d << endl; 
    cout << b2 << endl; 

    const int b = (b2 == &d) ? 3 : 4; ///Case1: b = 3; 
    const int c = (reinterpret_cast<char*>(b2) == reinterpret_cast<char*>(&d)) ? 3 : 4; //Case 2: c = 4; 

    std::cout << b << c << std::endl; 

    return 0; 
} 
+0

+1,只是因爲這是一個很好的例子,並且很好地說明了多重繼承對指針的影響 – ltjax

+0

+1。一個很好的例子,特別是沒有虛擬內部真正派人通過鈴聲。 – WhozCraig

回答

9

d是C型的當轉換一個指針到C的指針B,它被調整,使得它指向C的乙子對象(需要通常這樣ajustement有多重繼承,如果沒有B需要,那麼A將會有一個作爲C繼承自A和B)。因此在分配和比較時間完成調整。

在其他兩個時間,& d被轉換爲void *(隱式地)或char *(帶reinterpret_cast)並且沒有調整完成(您明確要求reinterpret_cast沒有調整,並且沒有理由在轉換爲void *時做一個調整,它會使沒有很好理由的往返過程複雜化,因此對於A)也會有類似的結果,因此表示形式不同。

順便說一下,如果您使用reinterpret_cast<B*>(&d),則不會再進行調整,但將結果作爲B *使用會導致問題。

3

在情況1中,比較自動將C指針轉換爲B指針。在這種情況下,這意味着實際地址會發生變化,因爲您使用多重繼承,而B在基類的列表中處於第二位。更具體地說,指針必須被(至少)sizeof(A)抵消。然而,在第二種情況下,不執行這種自動轉換,所以「A前綴」使得兩個指針不相等。

+0

沒有「自動演員」這樣的事情。轉換是顯式轉換,它存在於源代碼中。 – curiousguy

+0

你是什麼意思?很明顯,案例1中存在一個倒戈,但它並不明確。 – ltjax

+0

不明確的演員陣容根本不是演員陣容。演員陣容可以是C風格,功能風格或新風格:'(T)x','T(x)','static_cast (x)'...... – curiousguy