irappa
irappa

Reputation: 749

interpreting object addresses with reintepret_cast

The following code gives the output as 136. But I could not understand how the first two address comparisons are equal. Appreciate any help to understand this. Thank you.

#include <iostream>

class A
{
public:
    A() : m_i(0){ }
protected:
    int m_i;
};

class B
{
public:
    B() : m_d(0.0) { }
protected:
    double m_d;
};

class C : public A, public B
{
public:
    C() : m_c('a') { }
private:
    char m_c;
};

int main( )
{
 C d;
 A *b1 = &d;
 B *b2 = &d;

const int a = (reinterpret_cast<char *>(b1) == reinterpret_cast<char *>(&d)) ? 1 : 2;
const int b = (b2 == &d) ? 3 : 4;
const int c = (reinterpret_cast<char *>(b1) == reinterpret_cast<char *>(b2)) ? 5 : 6;

std::cout << a << b << c << std::endl;

return 0;
}

Upvotes: 5

Views: 224

Answers (3)

yzt
yzt

Reputation: 9113

In this kind of inheritance (when virtual is not involved,) each instance of C will have the following layout:

  • First, there will be all members of A (which is just m_i, a 4-byte integer)
  • Second will be all members of B (which is just m_d, an 8-byte double)
  • Last will be all members of C itself, which is just a character (1 byte, m_c)

When you cast a pointer to an instance of C to A, because A is the first parent, no address adjustment takes place, and the numerical value of the two pointers will be the same. This is why the first comparison evaluates to true. (Note that doing a reinterpret_cast<char *>() on a pointer never causes adjustment, so it always gives the numerical value of the pointer. Casting to void * would have the same effect and is probably safer for comparison.)

Casting a pointer to an instance of C to B will cause a pointer adjustment (by 4 bytes) which means that the numerical value of b2 will not be equal to &d. However, when you directly compare b2 and &d, the compiler automatically generates a cast for &d to B *, which will adjust the numerical value by 4 bytes. This is the reason that the second comparison also evaluates to true.

The third comparison return false because, as said before, casting a pointer to an instance of C to A or to B will have different results (casting to A * doesn't do adjustment, while casting to B * does.)

Upvotes: 0

Captain Obvlious
Captain Obvlious

Reputation: 20063

When you use multiple inheritance like in your example the first base class and the derived class share the same base address. Additional classes you inherit from are arranged in order at an offset based on the size of all preceding classes. The result of the comparison is true because the base address of d and b1 are the same.

In your case, if the size of A is 4 bytes then B will start at base address of A + 4 bytes. When you do B *b2 = &d; the compiler calculates the offset and adjusts the pointer value accordingly.

When you do b2 == &d an implicit conversion from type 'C' to type 'B' is performed on d before the comparison is done. This conversion adjusts the offset of the pointer value just as it would in an assignment.

Upvotes: 1

microtherion
microtherion

Reputation: 4048

It’s pretty typical for a derived class (like C here) to be laid out in memory so it starts with its two base classes (A and B), so the address of an instance of type C would be identical to the address of the instance its first base class (i.e. A).

Upvotes: 0

Related Questions