2

我真的很困惑。我跑進了以下情況,其中C從A和B都繼承,但根據事情是如何分配的,我得到不同的行爲:從基類指針訪問派生類成員

  • 如果我new一個C實例,並將其存儲在一個A指針,然後將它的值分配給B指針,並使用A指針調用A的方法,並使用B指令的方法調用B指針,我得到奇怪的東西......(請參閱測試1)。

  • 如果我new一個C實例,並將其存儲在一個C指針,然後分配給它的價值的AB指針,並調用使用A指針的A的方法,以及BB的方法指針,我得到我期望的...(見測試2)。

我的問題是:爲什麼測試1的行爲方式呢?

A類

class A 
{ 
public: 
    A() { aMember = 'A'; } 
    virtual ~A() {} 
    virtual char getAMember() { return aMember; } 
private: 
    char aMember; 
}; 

B類

class B 
{ 
public: 
    B() { bMember = 'B'; } 
    virtual ~B() {} 
    virtual char getBMember() { return bMember; } 
private: 
    char bMember; 
}; 

C類

class C : public A, public B 
{ 
public: 
    C() : A(), B() {} 
    virtual ~C() {} 
}; 

主要有Test1的&的Test2

#include <cstdio> 

int main(void) 
{ 
    C* c; 
    A* a; 
    B* b; 

    printf("Test 1\n"); 

    a = new C(); 
    b = (B*)a; 

    printf("a->getAMember(): %c\n",a->getAMember()); // prints A 
    printf("b->getBMember(): %c\n",b->getBMember()); // prints A ?! 

    printf("Test 2\n"); 

    c = new C(); 
    a = c; 
    b = c; 

    printf("a->getAMember(): %c\n",a->getAMember()); // prints A 
    printf("b->getBMember(): %c\n",b->getBMember()); // prints B 

    return 0; 
} 
+0

指針轉換的危險之處在於編譯器會讓你做到,即使它沒有意義。 – 2015-03-31 14:46:57

+0

你也可以考慮閱讀以下文章:http://stackoverflow.com/questions/9374244/casting-pointer-to-base-class-into-a-pointer-to-derived-class – 2015-03-31 14:52:06

回答

3

您使用的是邪惡的C樣式轉換,在這種情況下相當於reinterpret_cast。這將A子對象的地址重新解釋爲B子對象的地址,該子對象實際上位於另一個地址;演員表無效,如果您試圖通過該指針訪問B,則會導致未定義的行爲。

使用dynamic_cast可以在同一個完整對象的多態基類子對象之間安全地交叉轉換(如果要轉換指針,請記住檢查結果);或static_cast到派生類(在這種情況下,爲C*),如果您確定您指向的是該類型的對象。

在第二種情況下,您可以安全地將派生類轉換爲基類,因此所有內容都可以很好地定義,無需任何投射。

1

這是因爲此鑄b = (B*)a;導致未定義的行爲。像這樣施放是強制類型的。你應該使用dynamic_cast。

a = new C(); 
b = dynamic_cast<B*>(a); 

這將允許運行時間實際檢查由於您的虛擬功能,以及產生正確的結果的類型。如果演員陣容不合適,將導致nullptr

相關問題