tunnuz
tunnuz

Reputation: 24008

Oddity with multiple inheritance from two template parameters?

#include <iostream>

using namespace std;

template <typename E1, typename E2>
class Mix : public E1, public E2
{
public:
    Mix() : E1(1), E2(2)
    {  
        // Set nothing here
        cerr << "This is " << this << " in Mix" << endl;
        print(cerr);
    }

    void print(ostream& os)
    {
        os << "E1: " << E1::e1 << ", E2: " << E2::e2 << endl;
        // os << "E1: " << e1 << ", E2: " << e2 << endl; won't compile
    }
};

class Element1
{
public:
    Element1(unsigned int e) : e1(e)
    {
        cerr << "This is " << this << " in Element1" << endl;
    }

    unsigned int e1;
};

class Element2
{
public:
    Element2(unsigned int e) : e2(e)
    {
        cerr << "This is " << this << " in Element2" << endl;
    }

    unsigned int e2;
};


int main(int argc, char** argv)
{
   Mix<Element1, Element2> m; 
}

Now, since we're equally inheriting from the two template parameter classes, I would expect this to be the same in the two constructors, but this is not the case. Here is the run log:

This is 0x7fff6c04aa70 in Element1
This is 0x7fff6c04aa74 in Element2
This is 0x7fff6c04aa70 in Mix
E1: 1, E2: 2

As you can see, while this is the same in Element1 and Mix, this is not true for Element2. Why is that? Also, I would expect to have access to e1 and e2 from the base classes. Can you explain this behavior?

Upvotes: 1

Views: 93

Answers (1)

urzeit
urzeit

Reputation: 2909

The Element Mix contains an Element1 and an Element2. These are - perhaps implementation specifically aligned - written after one another in memory. If you use Mix as Element1, this will point to the first of the two (with size of Element1), if you use it as Element2 it will point to the second (with size of Element2) and if you use it as Mix it will point to the base address, which is the same as Element1s base address, but has a differenz size (at least size of Element1 + size of Element2).

Edit: You can verify this by outputting the size too:

#include

using namespace std;

template <typename E1, typename E2>
class Mix : public E1, public E2
{
public:
    Mix() : E1(1), E2(2)
    {  
        // Set nothing here
        cerr << "This is " << this << " + " << sizeof(*this) << " in Mix" << endl;
        print(cerr);
    }

    void print(ostream& os)
    {
        os << "E1: " << E1::e1 << ", E2: " << E2::e2 << endl;
        // os << "E1: " << e1 << ", E2: " << e2 << endl; won't compile
    }
};

class Element1
{
public:
    Element1(unsigned int e) : e1(e)
    {
        cerr << "This is " << this << " + " << sizeof(*this) << " in Element1" << endl;
    }

    unsigned int e1;
};

class Element2
{
public:
    Element2(unsigned int e) : e2(e)
    {
        cerr << "This is " << this << " + " << sizeof(*this) << " in Element2" << endl;
    }

    unsigned int e2;
};


int main(int argc, char** argv)
{
   Mix<Element1, Element2> m; 
}

Output:

This is 0x7fffc9cad310 + 4 in Element1
This is 0x7fffc9cad314 + 4 in Element2
This is 0x7fffc9cad310 + 8 in Mix
E1: 1, E2: 2

Upvotes: 1

Related Questions