2011-05-14 57 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类,任何私有的非静态成员对象都可能以“优化”的方式进行分配,这可能会导致基础和派生对象的东西不完全是一个干净的“切片”。