Inherited sequential layout in C++

Posted in software by Christopher R. Wirz on Sat Sep 16 2017



In a previous post, I discussed how any pointer can be cast to a defined structure in order to have access to private members. The question now is how this works when inheritance is involved.

First, define a series of classes for composition and inheritance.


#include <stdio.h>
#include <vector>

class ElementClass {
    private:
    double r = 8.1;
    std::vector<int> vect1{ 10, 20, 30, 5, 1 };
    double m = 7.4;
};

class BaseClass {
    private:
    int i = 4;
    ElementClass c;
};

class BaseClass2 {
    private:
    double r2 = 7.1;
    double m2 = 6.7;
    std::vector<int> vect2{ 3, 14, 15, 92 };
};

class DerivedClass : BaseClass, BaseClass2 {
    private:
    double d = 9.8;
};

It is expected that precedence will take place as follows:

  1. First base class
  2. Members of first base class
  3. Second base class
  4. Members of second base class
  5. Derived class
  6. Members of derived class

Based on the code above, we assume the sequential layout of the derived class to be as follows.


struct DerivedClass_def {
    // BaseClass
    int i;

    // ElementClass
    double r;
    std::vector<int> vect1;
    double m;

    // BaseClass2
    double r2;
    double m2;
    std::vector<int> vect2;

    // DerivedClass
    double d;
};


This can be tested by casting the pointer and inspecting the members.


int main()
{
    DerivedClass* d = new DerivedClass();
    DerivedClass_def* df = (DerivedClass_def*)d;

    printf("i = %d\n", df->i);
    printf("r = %.1f\n", df->r);
    printf("m = %.1f\n", df->m);
    printf("vect1.size = %d\n", df->vect1.size());
    printf("vect1 = {");
    if (df->vect1.size()>0){
        printf("%d", df->vect1[0]);
    }
    for (int n = 1; n < df->vect1.size(); n++){
        printf(", %d", df->vect1[n]);
    }
    printf("};\n");
    printf("r2 = %.1f\n", df->r2);
    printf("m2 = %.1f\n", df->m2);
    printf("vect2.size = %d\n", df->vect2.size());
    printf("vect2 = {");
    if (df->vect2.size()>0){
        printf("%d", df->vect2[0]);
    }
    for (int n = 1; n < df->vect2.size(); n++){
        printf(", %d", df->vect2[n]);
    }
    printf("};\n");
    printf("d = %.1f\n", df->d);

    delete d;
    d = NULL;
    return 0;
}


Running the code gives the following output.


i = 4
r = 8.1
m = 7.4
vect1.size = 5
vect1 = {10, 20, 30, 5, 1};
r2 = 7.1
m2 = 6.7
vect2.size = 4
vect2 = {3, 14, 15, 92};
d = 9.8

It is seen that the code successfully displays the content of the derived class, and all base classes. Memory layout (in this case) is guaranteed.

What's next? You can try this yourself.