Question

I'm a bit confused about a "multiple inheritance problem". Consider the following hunk of code:

#include <iostream>

struct iface
{
    virtual void foo () = 0;
    virtual ~iface () {}
};

struct wrapped
{
    virtual void foo ()
    {
        std::cerr << "wrapped\n";
    }
};

struct impl : public wrapped, public iface
{
};

iface* factory ()
{
    return new impl;
}

int main ()
{
    iface *object = factory ();

    object->foo();

    delete object;

    return 0;
}

This is abstracted out of some code that's using the pimpl idiom. The idea is that wrapped is some complicated class with all sorts of other bells and whistles. iface just makes a particular facet of wrapped visible and the factory() function builds an impl class that implements iface by using wrapped. In my real code, the wrapped class comes from a library with an enormous tree of headers, so I define impl in a separate compilation unit to avoid the rest of my application having to pull them in.

Anyway, what I pasted does not compile, and gives the following error:

$ g++ -o test test.cc
test.cc: In function ‘iface* factory()’:
test.cc:23:16: error: cannot allocate an object of abstract type ‘impl’
     return new impl;
                ^
test.cc:17:8: note:   because the following virtual functions are pure within ‘impl’:
 struct impl : public wrapped, public iface
        ^
test.cc:5:18: note:     virtual void iface::foo()
     virtual void foo () = 0;
                  ^

Obviously, I can avoid the error by writing a concrete implementation of foo in impl that forwards to wrapped::foo(), but I don't understand why the compiler doesn't pick up the implementation from the wrapped class.

I assume that somehow the "foo" from iface and the "foo" from wrapped end up being different when doing name resolution (is that the right word) for impl, but I don't really understand why.

Can someone explain what's going on?

Was it helpful?

Solution

If any virtual function of a class is a pure virtual then the class is absrtract. Class impl has two member functions with the same name

iface::foo

and

wrapped::foo

The first member function of class impl is pure virtual, so the class is abstract. The compiler may not create an object of an abstract class.

OTHER TIPS

impl has two entirely separate methods, iface::foo, which is pure, and wrapped::foo. There's no name resolution — virtual function calls are dispatched by a structure called vtable, which holds pointers to implementations. A class has separate vtable for each of its direct ancestors, at least in cases without virtual inheritance. Synonymous virtual functions from different ancestors end up in different vtables; the compiler has no way of "combining" them. C++ doesn't have mixins.

Obviously, I can avoid the error by writing a concrete implementation of foo in impl that forwards to wrapped::foo()

Better yet, don't use double inheritance — do something like

struct impl : public iface
{
    virtual void foo ()
    {
        wr.foo ();
    }
private:
    wrapped wr;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top