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()
{
c
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.
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.
- 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".