Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix "error: no matching function for call to" when inheriting twice from a base class

I am currently trying to implement a hirachy of inherited classes in my project. Therefore I am using member initializer-lists and "pipe" a reference to a variable all the way down to the base class. I am really not sure, why I am getting a compiler error.

I have already tried to change the reference "int &id" to a pointer "int* id". The example below above is just a minimal example that points out my problem:

class Base
{
public:
    int& m_id;

    Base(int &id)
        : m_id(id)
    {
    }
};

class Derived1: virtual public Base
{
public:
    Derived1(int &id) : Base(id)
    {
    };
};

class Derived2: public Derived1
{
public:
    Derived2(int &id) : Derived1(id)
    {
    };
};

int main()
{
   int i = 13;
   Derived2 Test(i);
}

I am getting the following error message when trying to compile:

"error: no matching function for call to ‘Base::Base()’"

Any idea, what I am doing wrong?

Thanks for your help.

like image 673
nilsmelchert Avatar asked May 17 '19 10:05

nilsmelchert


2 Answers

Virtual inheritance and virtual functions are different concepts.

Virtual inheritance is special in that virtual bases need to be explicitly initialized by all derived classes. In this case, Derived2 tries to delegate the initialization of Base to Derived1, but that's not valid. What the constructor of Derived2 actually does is to call the default constructor of Base because of the omission of a mem-initializer that initializes the Base.

You should call the constructor of Base explicitly:

class Derived2 :public Derived1 {
public:
    Derived2(int &id) : Base(id), Derived1(id)
    {
    };
};

Of course, if Derived1 were not to virtually derive from Base, then Derived1's derived classes can just rely on Derived1's constructor to initialize Base. So another fix, depending on your situation, is to simply remove the virtual in the base-specifier:

class Derived1 :public Base {
public:
    Derived1(int &id) :Base(id)
    {
    };
};

class Derived2: public Derived1 {
public:
    Derived2(int &id) :Derived1(id)
    {
    };
};
like image 134
L. F. Avatar answered Nov 15 '22 04:11

L. F.


Virtual inheritance is a strange beast. It requires that the most-derived class initializes the virtual base classes. In your case, that initialization is missing. This should do it:

class Derived2: public Derived1
{
public:
    Derived2(int &id) : Base(id), Derived1(id)
    {
    }
};
like image 20
j6t Avatar answered Nov 15 '22 04:11

j6t