0

I've come across a problem in a class hierarchy I couldn't solve so far. Below you get the minimal example where the template Base class itself inherits from another class that is not a template (called AbsoluteBase in the example below). The class Derived then inherits from Base with its template argument also being Bases' template argument:

#include <iostream> 
using namespace std;

class AbsolutBase {
    protected:
        int number;

        AbsoluteBase(int _number) {
            number = _number;
        }
        virtual ~AbsoluteBase() {}
        virtual void print() const = 0;
};

template <typename T> class Base : virtual public AbsoluteBase {
    public:
        Base(int _number) : AbsoluteBase(_number) {}

        virtual void print() const {
            cout << number << endl;
        }
};

template <typename T> class Derived : public Base<T> {
    public:
       Derived(int _number) : Base<T>::Base(_number) {}
};

int main() {
    Derived<char> object(100);
    object.print();
}

So each constructor calls the constructor of its parent and passes an integer as argument all the way down to AbsoluteBase. But when compiling the code I get:

error: no matching function for call to 'AbsoluteBase::AbsoluteBase()'
note: candidates are: AbsoluteBase::AbsoluteBase(int)
note: candidate expects 1 argument, 0 provided

Making an instance of Base works just fine but when calling its constructor in the initialization list of Derived, the compiler wants AbsolutBase() as constructor even though the integer argument is given. Obviously, when defining a default constructor in AbsoluteBase the print() function outputs garbage as no value has been passed to number.

So something has to be wrong with my call of Base<T>::Base(int) but I can't see what it is. I am grateful for every explanation and help!

Greetings, Benniczek

3 Answers 3

1

AbsoluteBase is a virtual base class. As such, it must be initialized by the constructor of the most-derived class. Your initializer AbsoluteBase(_number) is valid, but it is only used if you instantiate an object of type Base<T> directly.

The best solution is probably not to make AbsoluteBase a virtual base class.

The reason for this rule is:

class Silly: public Base<int>, Base<long>
{
public:  
    Silly() : Base<int>::Base(1), Base<long>::Base(2) {}
};

There is only one AbsoluteDerived object (that's what virtual means in this context), so is it initialized with 1 or 2?

Sign up to request clarification or add additional context in comments.

Comments

0

Because of virtual inheritance. When base class inherits virtually from another class, the child class of base it must also call constructor of virtual parent of its parent. Since you didn't do this, compiler is trying to call no-argument AbsoluteBase's ctor. So you just have to code as follows:

template <typename T> class Derived : public Base<T> {
    public:
       Derived(int _number) : AbsoluteBase(_number), Base<T>::Base(_number) {}
};

1 Comment

Thank you very much, I didn't know this rule for virtual inheritance.
0

You declared Absolute Base as class AbsolutBase without the e. Compiles just fine with the typo fixed.

Edit: It also will not compile if you have class base doing virtual inheritance from Absolute. Unless you need virtual inheritance (using multiple inheritance?) you can declare it class Base : public AbsoluteBase

If you do need virtual inheritance (the diamond problem) you'll need to initialize AbsoluteBase in your Derived class. Given that Base virtually inherits from AbsoluteBase, Derived could also inherit from a Base2 which also virtually inherits from AbsoluteBase (this is the point of virtual inheritance, one class can inherit from two different classes that themselves inherit from a common base). As it is a virtual inheritance, there can be only 1 AbsoluteBase even though Base and Base2 could inherit from AbsoluteBase, so how does it get initialized? This is why Derived is required to initialize it directly, so that when the 1 copy of AbsoluteBase is made, it is well understood how it will be initialized.

Again, that is messy, if you don't need virtual inheritance (you probably don't I'd guess...) you can just make Base inherit from AbsoluteBase publically and call it a day.

1 Comment

Now I feel dumb because of the typo... But it isn't there in my compiled code, just in my post above. Concerning virtual inheritance: Ah good, I didn't know that... I used virtual inheritance because the diamond problem might occur in further code but didn't know this rule for initialization in the most derived class. Thanks for that!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.