8

I'm not exactly sure the terminology to use, but here's my example:

class Base {
public:
    virtual void test() = 0;
};

class Mixin {
public:
    virtual void test() { }
};

class Example : public Base, public Mixin {
};

int main(int argc, char** argv) {
    Example example;
    example.test();
    return 0;
}

I want my Mixin class to implement the pure virtual function Base::test, but when I compile this, it says:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:15:13: error: cannot declare variable ‘example’ to be of abstract type ‘Example’
     Example example;
             ^
test.cpp:11:7: note:   because the following virtual functions are pure within ‘Example’:
 class Example : public Base, public Mixin {
       ^
test.cpp:3:18: note:    virtual void Base::test()
     virtual void test() = 0;
                  ^
test.cpp:16:13: error: request for member ‘test’ is ambiguous
     example.test();
             ^
test.cpp:8:18: note: candidates are: virtual void Mixin::test()
     virtual void test() { }
                  ^
test.cpp:3:18: note:                 virtual void Base::test()
     virtual void test() = 0;
                  ^

I can add a using statement to make it not ambiguous:

class Example : public Base, public Mixin {
public:
    using Mixin::test;
};

But it says I still haven't implemented it:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:17:13: error: cannot declare variable ‘example’ to be of abstract type ‘Example’
     Example example;
             ^
test.cpp:11:7: note:   because the following virtual functions are pure within ‘Example’:
 class Example : public Base, public Mixin {
       ^
test.cpp:3:18: note:    virtual void Base::test()
     virtual void test() = 0;
                  ^

Is it possible to do this?

I know one option is to make Mixin inherit from Base, but in my case there's several derived classes and they don't share a common ancestor.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • _'I know one option is to make Mixin inherit from Base'_ IMHO this is contradictory for my understanding of **'Mixins'** ... – πάντα ῥεῖ Oct 22 '13 at 21:19
  • @g-makulik My point was that in situations like this, a *technical solution* to the problem is usually to make the class not a mixin, but in this case it doesn't work. The real class isn't named `Mixin`. – Brendan Long Oct 22 '13 at 21:36
  • 1
    Just a shot in the dark: A [CRTP](http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) might help out? – πάντα ῥεῖ Oct 22 '13 at 21:41
  • Other things come to mind: [Policy-Based Design](http://loki-lib.sourceforge.net/index.php?n=Main.Policy-basedDesign), [double-dispatch](http://en.wikipedia.org/wiki/Double_dispatch) ... – πάντα ῥεῖ Oct 22 '13 at 22:52

2 Answers2

8

You cannot directly have a class override a method not of its base class. But you can sort-of of do it in a roundabout way. I'll present two such approaches - I prefer the second.

Approach 1

This is described by Daniel Paul in a post on thinkbottomup.com.au, entitled C++ Mixins - Reuse through inheritance is good... when done the right way.

In your case, this is what it would look like:

class Base {
public:
    virtual void test() = 0;
};

template <typename T>
class Mixin : public T {
public:
    virtual void test() override { /*... do stuff ... */ }
};

class UnmixedExample : public Base {
    /* definitions specific to the Example class _not_including_
       a definition of the test() method */
};

using Example = class Mixin<UnmixedExample>;

int main(int argc, char** argv) {
    Example{}.test();
    return 0;
}

Approach 2: CRTP!

CRTP is the "Curiously Recurring Template Pattern" - definitely follow that link if you haven't seen it before. With this approach, we'll be using the virtual inheritance specifier to avoid ambiguity, and unlike the previous approach - we will not be reversing the inheritance order of the Mixin and Example classes.

class Base {
public:
    virtual void test() = 0;
};

template <typename T>
class Mixin : virtual T {
public:
    virtual void test() override { /*... do stuff ... */ }
};

class Example : public virtual Base, public virtual Mixin<Base> {
    /* definitions specific to the Example class _not_including_
       a definition of the test() method */
};

int main(int argc, char** argv) {
    Example{}.test();
    return 0;
}

Note about both solutions:

  • Ain't it curious how the CRTP keeps recurring all over the place? :-)
  • The code I used is C++11 for pedagogical purposes, but the same would work in C++98.
Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
4

You cannot have a class override an unrelated class's virtual function. There are different things you could do to work around this. You can make the mixin a template that derives (virtually) from the type argument and use it as class Example : public virtual Base, Mixin, or you can add code in the final class to dispatch to the mixing:

void Derived::test() { Mixin::test(); }
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • David, as a learned gold-badge sage, would you mind having a look at my [alternative answer](http://stackoverflow.com/a/43668264/1593077)? – einpoklum Apr 28 '17 at 13:15
  • @einpoklum: The second approach is the same I mentioned in the text paragraph. You don't need virtual inheritance from the mix-in and you don't need CRTP. The first approach you have is extending the hierarchy rather than using mix-ins, it will also work, offering different advantages/disadvantages from the second approach. I still feel that the closes to the ideal of a mix-in is paying for the additional line required to just forward to the mixin – David Rodríguez - dribeas May 02 '17 at 09:50