1

I was debugging some legacy code and while doing that found some inconsistency in the address of this pointer in the class hierarchy like this:

#include <cstdio>
#include <vector>

class ROOT1 {
   public:
    ROOT1() {}
    void printsomething() { printf("ROOT1::printsomething %p\n", this); }
    virtual ~ROOT1() {}
};

class SUBROOT : public ROOT1 {
   public:
    SUBROOT() {}
    void printsomething() { printf("SUBROOT::printsomething %p\n", this); }
    virtual ~SUBROOT() {}
};

class ROOT2 {
   public:
    ROOT2() {}
    virtual ~ROOT2() {}
    void printsomething() { printf("ROOT2::printsomething %p\n", this); }
};

class CHILD : public ROOT2, public SUBROOT {
   public:
    CHILD() {}
    virtual ~CHILD() {}
    void printsomething() { printf("CHILD::printsomething %p\n", this); }
};
class GRANDCHILD : public CHILD {
   public:
    GRANDCHILD() {}
    virtual ~GRANDCHILD() {}
    void printsomething() { printf("GRANDCHILD::printsomething %p\n", this); }
};

int main() {
    try {
        GRANDCHILD* line = new GRANDCHILD;
        ROOT1* root1 = static_cast<ROOT1*>(line);
        SUBROOT* subroot = static_cast<SUBROOT*>(line);
        CHILD* child = static_cast<CHILD*>(line);
        ROOT2* root2 = static_cast<ROOT2*>(line);

        root2->printsomething();
        root1->printsomething();
        subroot->printsomething();
        child->printsomething();
        line->printsomething();

    } catch (const char* s) {
        printf("Throw %s, %d\n", s, sizeof(std::vector<void*>));
    }
}

LIVE

The output I am getting is:

ROOT2::printsomething 0x23cf2b0
ROOT1::printsomething 0x23cf2b8
SUBROOT::printsomething 0x23cf2b8
CHILD::printsomething 0x23cf2b0
GRANDCHILD::printsomething 0x23cf2b0

There is a difference between the addresses of 'this' pointer. If I just swap the order of inheritance, the addresses changes along the class hierarchy. i.e.

class CHILD :  public SUBROOT, public ROOT2

LIVE

Output:

ROOT2::printsomething 0xc9b2b8
ROOT1::printsomething 0xc9b2b0
SUBROOT::printsomething 0xc9b2b0
CHILD::printsomething 0xc9b2b0
GRANDCHILD::printsomething 0xc9b2b0

What could be the reason?

10
  • can't replicate, they are still inconsistent godbolt demo of gcc clang MSVC Commented Dec 6, 2024 at 8:45
  • i would be more interested in knowing what form of bugged compiler you are using that would produce ROOT2:: from child with your code .... technically your compiler would be bugged if it produces that result, but your code also has a typo, so i am not sure who to blaim Commented Dec 6, 2024 at 8:54
  • This is normal and expected. Try to draw the layout of either version of CHILD. Commented Dec 6, 2024 at 9:03
  • @AhmedAEK upcast with static_cast is always OK. Then it's multiple inheritance, isn't it expected that the subobjects on different branchs have different address? Commented Dec 6, 2024 at 9:06
  • @Oersted all versions of the code above will show CHILD::printsomething not ROOT2::printsomething, except when i added it myself to show that it still has different addrss, the code above should not produce ROOT2::printsomething except if the compiler is bugged or the question is wrong. Commented Dec 6, 2024 at 9:08

1 Answer 1

0

It is a matter of multiple inheritance.

Exactly to avoid multiple inheritance in java, a java class can extend only one single class, though then implement several interfaces (primarily this-bodyless APIs).

With multiple inheritance CHILD has a ROOT2 this and a SUBROOT this. This difference in addresses are due to the virtual method table of method pointers that are stored in the classes this. To pick the right inherited printsomething.

BTW you see here a clash of printsomethings of two different class lines in CHILD. This was thought to need avoidance in java.

Sign up to request clarification or add additional context in comments.

6 Comments

printsomething is not virtual (otherwise the output should always be GRANDCHILD::printsomething I think: godbolt.org/z/TGvKad56d).
@Oersted yes a virtual would have been a minor ambiguity problem in C++ too. But I could not refrain from remarking on printsomething here.
btw, I can't find, so far, a constraint in C++ to give the same memory location to base objects, in single inheritance. Yet I think that all compilers do so and I may well have missed some part of the standard on this topic.
A new CHILD addesses an object (memory block) as CHILD*. There is no other "base" object. The same address is used as ROOT2*. The object contains a vtable of methods, where some virtual ROOT2 methods are replaced by overriden CHILD methods. This technique is used to implement inheritance in probably all compilers. Only SUBROOT has an offset address in the object, with the SUBROOT data fields and vtable. No requirement.
of course they are base subobjects. as far as I dug, only the order in which they are created is specified, not the memory layout. vtable and offsets are an implementation detail and thus are not described in the standard.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.