Search code examples
c++multiple-inheritancethis-pointer

Does this pointer adjustment occur for non-polymorphic inheritance?


Does non-polymorphic inheritance require this pointer adjustment? In all the cases I've seen this pointer adjustment discussed the examples used involved polymorphic inheritance via keyword virtual.

It's not clear to me if non-polymorphic inheritance would require this pointer adjustment.

An extremely simple example would be:

struct Base1 {
    void b1() {}
};

struct Base2 {
    void b2() {}
};

struct Derived : public Base1, Base2 {
    void derived() {}
};

Would the following function call require this pointer adjustment?

Derived d;
d.b2();

In this case the this pointer adjustment would clearly be superfluous since no data members are accessed. On the other hand, if the inherited functions accessed data members then this pointer adjustment might be a good idea. On the other other hand, if the member functions are not inlined it seems like this pointer adjustment is necessary no matter what.

I realize this is an implementation detail and not part of the C++ standard but this is a question about how real compilers behave. I don't know if this is a case like vtables where all compilers follow the same general strategy or if I've asked a very compiler dependent question. If it is very compiler dependent, then that in itself would be a sufficient answer or if you'd prefer, you can focus on either gcc or clang.


Solution

  • Layout of objects is not specified by the language. From the C++ Draft Standard N3337:

    10 Derived Classes

    5 The order in which the base class subobjects are allocated in the most derived object (1.8) is unspecified. [ Note: a derived class and its base class subobjects can be represented by a directed acyclic graph (DAG) where an arrow means “directly derived from.” A DAG of subobjects is often referred to as a “subobject lattice.”

    enter image description here

    6 The arrows need not have a physical representation in memory. —end note ]

    Coming to your question:

    Would the following function call require this pointer adjustment?

    It depends on how the object layout is created by the compiler. It may or may not.

    In your case, since there are no member data in the classes, there are no virtual member functions, and you are using the member function of the first base class, you probably won't see any pointer adjustments. However, if you add member data, and use a member function of the second base class, you are most likely going to see pointer adjustments.

    Here's some example code and the output from running the code:

    #include <iostream>
    
    struct Base1 {
       void b1()
       {
          std::cout << (void*)this << std::endl;
       }
       int x;
    };
    
    struct Base2 {
       void b2()
       {
          std::cout << (void*)this << std::endl;
       }
       int y;
    };
    
    struct Derived : public Base1, public Base2 {
       void derived() {}
    };
    
    int main()
    {
       Derived d;
       d.b1();
       d.b2();
       return 0;
    }
    

    Output:

    0x28ac28
    0x28ac2c