1
#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?

tunnuz
  • 23,338
  • 31
  • 90
  • 128
  • 2
    Why should Element1 and Element2 have the same adrress? they are not the same object. – PlasmaHH Jul 11 '13 at 14:35
  • Also, you can get access to `e1` and `e2` from base class, just add `this->` before them. Look [here](http://stackoverflow.com/questions/3799495/template-inheritance-c). – awesoon Jul 11 '13 at 14:39
  • @soon thanks, I used to know about that, but temporarily forgot. :) – tunnuz Jul 11 '13 at 21:27
  • "_Also, I would expect to have access to e1 and e2 from the base classes._" Hug? What is the problem? – curiousguy Jul 15 '13 at 10:10

1 Answers1

1

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
urzeit
  • 2,863
  • 20
  • 36