开发者

About dynamic cast and address of base and derived objects

开发者 https://www.devze.com 2023-03-06 11:34 出处:网络
I was reading through some of effective c++ and I realized I may be incorrect in my thinking along the way.

I was reading through some of effective c++ and I realized I may be incorrect in my thinking along the way.

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;
}

The book stated that by using dynamic_cast with *void, I would get the starting address of an object however,开发者_运维百科 all of the addresses output of the same.

  1. When I just output the address of the plain old &b above, is the address displayed the starting address of the derived object or the base object within b?

  2. If I was incorrect or wrong about #1, how would I get the starting addresses of each subobject within b? Do I just manually have to offset and how does dynamic_cast work with this or just clarify what the author meant?


Most implementations of inheritance put the first base class subobject at the beginning of the derived class, so you really need two base classes, both with data members, to be able to see this. Consider:

#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";
}

Example output (from my machine; your results will be similar):

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

This tells us that the B1 subobject of D is located at the beginning, so it has the same address as the D object of which it is a subobject.

The B2 subobject is located at a different address, but when you use dynamic_cast<void*> on the pointer to the B2 subobject, it gives you the address of the D object of which it is a subobject.


The book was correct, a dynamic_cast to cv-qualified void* converts the pointer to a pointer to the most derived object pointed to by the pointer that you supply, so you get the starting address of the derived object. Both your output statements should print the same address (assuming there isn't a specific std::ostream and B* overload for operator<<) as b is the most derived object.

There is no reason the a base class subobject can't have the same starting address as a derived object and this is what often happens in many implementations, at least for the first base class subobject in a derived class.


This is all compiler and implementation dependent. In your case a B is a A + something, so it sotres the A then the B specific members. so the address of &b and the one displayed by your dynamic_cast ought to be the same.


  1. When I just output the address of the plain old &b above, is the address displayed the starting address of the derived object or the base object within b?

You could say "yes", it's the starting address of the base object class A within b (which is the same as the starting address of the derived object b itself) ... but the derived object is not really a "separate" object from the base-object. The derived object is also not something that will necessarily start with a fixed offset from the base object, especially if it's a non-POD class (plain-old-data-type) with virtual functions since the first address of both the base and derived objects is a pointer to a v-table specific to either the base or derived object. So you can't really "slice" apart a derived object into a "base-object" and derived object, other than the fact that for most compiler instances, the derived objects non-static data members will come after an offset from the non-static data memebers of the base-object. But again, arbitrary "slicing" will cause issues with the v-table pointer, and also for non-POD classes, any private non-static member objects may be allocated in an "optimized" fashion that may make the memory layout between the base and derived objects something that is not exactly a clean "slice".

0

精彩评论

暂无评论...
验证码 换一张
取 消