3

Can you explain the output of the following code? And what do I need to do to call the right base class constructor?

Thanks.

#include <vector>
#include <iostream>

template <class CONTAINER> class SequenceComposite {
protected:
    CONTAINER m_data;
public:
    typedef typename CONTAINER::value_type value_type;
    typedef typename CONTAINER::allocator_type allocator_type;
    typedef typename CONTAINER::size_type size_type;
    explicit SequenceComposite(const allocator_type& alloc = allocator_type()) : m_data(alloc) {
        std::cout << std::endl << "SequenceComposite(alloc)" << std::endl;
    }
    explicit SequenceComposite(size_type n, const value_type& val = value_type(),
        const allocator_type& alloc = allocator_type()) : m_data(n, val, alloc) {
        std::cout << std::endl << "SequenceComposite(n, val, alloc)" << std::endl;
    }
    SequenceComposite(const SequenceComposite& x) : m_data(x.m_data) {
        std::cout << std::endl << "SequenceComposite(x)" << std::endl;
    }

};

template <class DTYPE>
class VectorComposite : public virtual SequenceComposite< std::vector<DTYPE> > {
public:
    typedef typename VectorComposite::value_type value_type;
    typedef typename VectorComposite::allocator_type allocator_type;
    typedef typename VectorComposite::size_type size_type;
    explicit VectorComposite(const allocator_type& alloc = allocator_type()) : SequenceComposite< std::vector<DTYPE> >(alloc) {
        std::cout << "VectorComposite(alloc)" << std::endl;
    }
    explicit VectorComposite(size_type n, const value_type& val = value_type(),
        const allocator_type& alloc = allocator_type()) : SequenceComposite< std::vector<DTYPE> >(n, val, alloc) {
        std::cout << "VectorComposite(n, val, alloc)" << std::endl;
    }
    VectorComposite(const VectorComposite& x) : SequenceComposite< std::vector<DTYPE> >(x) {
        std::cout << "VectorComposite(x)" << std::endl;
    }

};

template<typename T> class MyModel : public virtual VectorComposite<T> {
    public:
        MyModel() {
            std::cout << "MyModel()" << std::endl;
        };
        MyModel(const MyModel<T> &vec) : VectorComposite<T>(vec) {
            std::cout << "MyModel(x)" << std::endl;
        }
        MyModel( size_t n, const T& value= 0) : VectorComposite<T>(n, value) {
            std::cout << "MyModel(n, val)" << std::endl;
        }
};

int main() {
    MyModel<float> c(4, 2.0);
    MyModel<float> e(c);

    VectorComposite<float> a(3, 2.0);
    VectorComposite<float> b(c);

    return 0;
}

Output:

SequenceComposite(alloc)
VectorComposite(n, val, alloc)
MyModel(n, val)

SequenceComposite(alloc)
VectorComposite(x)
MyModel(x)

SequenceComposite(n, val, alloc)
VectorComposite(n, val, alloc)

SequenceComposite(x)
VectorComposite(x)

I expected

SequenceComposite(n, val, alloc)
VectorComposite(n, val, alloc)
MyModel(n, val)

SequenceComposite(x)
VectorComposite(x)
MyModel(x)
...
Michael
  • 1,464
  • 1
  • 20
  • 40
  • 4
    See: http://stackoverflow.com/questions/2126522/c-virtual-inheritance – CB Bailey Mar 14 '13 at 11:16
  • Why do you even use `virtual` inheritance? – Grizzly Mar 14 '13 at 11:17
  • @PeterWood: While I agree that the expected result should be explicitly spelled out, it's not difficult to see that e.g. in the first case it seems that the "wrong" `SequenceComposite` constructor is called. – Jon Mar 14 '13 at 11:18
  • @Jon We all have different ways of replying. I want to improve the question, not necessarily to answer it. – Peter Wood Mar 14 '13 at 11:24
  • @Grizzly Because of http://stackoverflow.com/a/11954411/861164. James Kanze suggested "Note the virtual inheritance. This should generally be the default when you're extending interfaces." I want to exapnd the interface – Michael Mar 14 '13 at 11:26
  • 1
    @Michael: You don't expand **an** interface in the typical sense, since you base class has member variables (and maybe even non pure virtual member functions?). An interface in the typical sense is a base class which only describes the interface (well obviously) without containing any implementation details. In that case `virtual` inheritance is useful to avoid the [diamond inheritance problem](http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem). Unless your class risks running into that problem there is little reason to use `virtual` inheritance – Grizzly Mar 14 '13 at 11:49
  • @CharlesBailey If the constructor of `VectorComposite` doesn't do anything itself could I just omit its call and only call the constructor of `SequenceComposite`? – Michael Mar 14 '13 at 11:51

1 Answers1

2

Virtual base classes are initialized from the constructor of the most derived type. So in the first two examples, the default constructor for SequenceComposite is called. That's the one that takes an allocator_type with a default argument. To use a different constructor, call it from the initializer list of the most derived type.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165