2011-05-14 66 views
1

我讀通過一些有效的C++,我意識到我可能是我前進的道路上思想不正確。關於動態演基地的地址和派生對象

class A 
{ 
    public: 
    void laka() 
    { 
     const void * raw = dynamic_cast<const void*>(this); 
     cout << raw << endl; 
    } 

    virtual ~A() = 0; 
}; 

A::~A() {} 
class B : public A 
{ 
public: 
    void ditka() {} 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    B b; 
    cout << &b << endl; 
    b.laka(); 

    return 0; 
} 

書指出,通過使用dynamic_cast的有*空,我會得到一個物體的起始地址然而,所有相同的地址輸出的。

  1. 當我只輸出上述普通的舊& B的地址,是地址顯示的派生對象或b內的基本對象的起始地址?

  2. 如果我是不正確的或錯誤關於#1,我怎麼會得到在b中的每個子對象的起始地址?我是否需要手動抵消以及dynamic_cast如何處理這個問題,或者只是澄清作者的意思?

回答

5

繼承的大多數實現都將第一個基類子對象放在派生類的開頭,因此您確實需要兩個具有數據成員的基類才能看到它。試想一下:

#include <iostream> 

struct B1 { 
    int x; 
    virtual ~B1() { } 
}; 

struct B2 { 
    int y; 
    virtual ~B2() { } 
}; 

struct D : B1, B2 { }; 

int main() { 
    D x; 
    B1* b1_ptr = &x; 
    B2* b2_ptr = &x; 
    std::cout << "original address:  " << &x << "\n"; 

    std::cout << "b1_ptr:    " << b1_ptr << "\n"; 
    std::cout << "dynamic_cast b1_ptr: " << dynamic_cast<void*>(b1_ptr) << "\n"; 

    std::cout << "b2_ptr:    " << b2_ptr << "\n"; 
    std::cout << "dynamic_cast b2_ptr: " << dynamic_cast<void*>(b2_ptr) << "\n"; 
} 

輸出示例(從我的機器,你的結果將是相似的):

original address:  0030FB88 
b1_ptr:    0030FB88 
dynamic_cast b1_ptr: 0030FB88 
b2_ptr:    0030FB90 
dynamic_cast b2_ptr: 0030FB88 

這告訴我們,DB1子對象位於開始,所以它具有相同的地址作爲它的子對象的D對象。

B2子對象位於不同的地址,但是當你使用dynamic_cast<void*>上的指針到子對象的B2,它給你的D對象,它是一個子對象的地址。

0

這是所有依賴於編譯器和實現的。在你的情況下,一個B是一個A +的東西,所以它攪動了A,然後是B特定的成員。所以& b和dynamic_cast顯示的地址應該是相同的。

0

這本書是正確的,一個dynamic_castCV-合格void*指針轉換爲指針到最派生類對象由您提供的,所以你得到的派生對象的起始地址的指針指向。無論你的輸出語句應打印相同的地址(假設沒有具體std::ostreamB*過載operator<<)爲b是最派生的對象。

沒有理由說基類子對象不能有與派生對象相同的起始地址,這是許多實現中經常發生的事情,至少對於派生類中的第一個基類子對象是如此。

+0

啊,所以如果我有A 將導致指向最大派生的指針在這種情況下是指向D的指針。我正確嗎? – Ilya 2011-05-14 23:29:15

+0

@伊利亞:是的,你是對的。 – 2011-05-14 23:37:42

+0

好的,謝謝。得到它了。 – Ilya 2011-05-14 23:37:53

0
  1. 當我只輸出上述普通的舊& B的地址時,在地址 顯示的 的起始地址派生的對象或B內的基礎對象 ?

你可以說「是」,它的基本對象類Ab的起始地址(這是一樣的派生類對象b本身的起始地址)... ...但派生對象實際上並不是一個與基礎對象「分離」的對象。派生對象也不是必須以基礎對象的固定偏移量開始的,特別是如果它是一個非POD類(普通舊數據類型),它具有虛函數,因爲基類和派生類型的第一個地址對象是指向特定於基本對象或派生對象的V表的指針。因此,除了對於大多數編譯器實例,派生對象非靜態數據成員將在非偏移量之後出現的事實之外,您不能真正將派生對象「分割」爲「基礎對象」和派生對象基礎對象的靜態數據存儲器。但同樣,任意的「切片」會導致v-表指針的問題,而且對於非POD類,任何私有的非靜態成員對象都可能以「優化」的方式進行分配,這可能會導致基礎和派生對象的東西不完全是一個乾淨的「切片」。