4

While going through this C++ FAQ https://isocpp.org/wiki/faq/mixing-c-and-cpp#cpp-objs-passed-to-c I encountered the statement

Most C++ compilers use a binary object layout that causes this conversion to happen with multiple inheritance and/or virtual inheritance.

I could not understand the meaning and application of it. As per the C++ FAQ this object layout mechanism helps C++ compiler in the below mentioned check

In C++ it is easy to check if a Derived* called dp points to the same object as is pointed to by a Base* called bp: just say if (dp == bp) .... The C++ compiler automatically converts both pointers to the same type, in this case to Base*, then compares them. Depending on the C++ compiler’s implementation details, this conversion sometimes changes the bits of a pointer’s value.

Could any one help to understand the binary object layout of any popular C++ compilers and what possible changes and the corresponding mechanism for changes in the bits of a pointer’s value. and How it helps in comparing the pointers of Base/Derived classes.

Edit : Please explain why the below is also a valid statement.

NOTE: you must be especially careful when converting both to void* since that conversion will not allow either the C or C++ compiler to do the proper pointer adjustments! The comparison (x == y) might be false even if (b == d) is true:

Krishna Oza
  • 1,390
  • 2
  • 25
  • 50

1 Answers1

8

In this context, "binary object layout" means "how the binary data comprising the object is layed out in memory."

Consider this C++ code:

struct Left
{
  int ll;
};

struct Right
{
  int rr;
};

struct Derived : Left, Right
{
  int dd;
};

One possible way to organise these in memory (conceptually) is as follows:

+ Derived ----------------+
| + Left +  + Right +     |
| | ll   |  | rr    |  dd |
| +------+  +-------+     |
+-------------------------+

Of course, the class is just 3 ints, so with the above conceptual layout, the real layout would be just this:

+ Derived------+
| ll | rr | dd |
+--------------+

Now imagine this code:

Derived d;
Dervied *pd = &d;
Left *pl = &d;
Right *pr = &d;

pd points to the start of d, which is the same as the start of its ll member.

pl will point at the Left subobject of d. The start of Left is the start of the ll member. When comparing pl == pd, pd needs to be converted to type Left*. Remember that pd already points to the start of ll, so no change of the value of pd needs to happen. It's purely a conceptual conversion (a change of type).

pr points to the Right subobject of d. Since a Right object starts with the rr member, pr points to rr. Again, doing pr == pd requires pd to be converted to type Right*. The Right subobject of d starts with the rr member, but pd points to the address of the ll member. Threfore, the value (= bits) of pd must be changed by this conversion (incremented by the size of one int) to point to rr instead. Actually, exactly this conversion already happened once when converting &d from Derived* to Right* in order to initialise pr with it.

This should also explain why comparing in void* type doesn't work. Clearly, &d.ll != &d.rr, even though pl == pr.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • How do I now handle a condition where I need to implement my own increment `++` operator needs to be overloaded for the above `structs`. Also can you refer to document something like C++ std etc. – Krishna Oza Mar 19 '15 at 14:16
  • Isn't that when we are using `&d` for all above assignments the address of `ll` will be assigned to each pointer type. Also why always `pd` has to be adjusted cant we adjust `pl` or `pr` or it is implementation defined. – Krishna Oza Mar 19 '15 at 14:18
  • @Krishna_Oza Derived-to-base conversion: C++11 4.10/3. Equality comparison: 5.10/1. But if you're still learning these concepts, you should probably be reading a [good book](http://stackoverflow.com/q/388242/1782465) rather than the C++ standard. It's the most authoritative source, but it's *hard* to read. – Angew is no longer proud of SO Mar 19 '15 at 16:03
  • @Krishna_Oza And it's always the pointer to derived which must be converted to the type of pointer to base. The conversion which I talked about for `==` naturally also happens for the simple assignment `pr = &d`. – Angew is no longer proud of SO Mar 19 '15 at 16:04