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.
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.
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;
}
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: