Search code examples
c++interfacec++17mixinscrtp

Static interface - CRTP? Mixin? Other?


I am interrested in interface implementation. I know the standard way of doing so is to code a class having pure virtual methods which is going to be used as interface, for instance:

class Interface {
public:
  virtual void doSometing() = 0;
}

and to have it used:

class Implementation : public Interface {
public:
  virtual void doSomething() override { ... }
}

Or even better to apply NVI (non virtual interface).

But all those use virtual functions which I am trying to avoid - as I am coding for embedded where performance loss due to vtable indirections must be considered.

Threfore I focused onto 'static polymorphism' and try to use CRTP to implement the interfaces:

template<typename T>
class Interface {
public:
  void doSomething() {
    static_cast<T&>(*this)._doSomething();
}

class Implementation : public Interface<Implementation> {
public:
  void _doSomething() { /* Do implementation specific stuff here */ }
}

class Implmentation2 : public Interface<Implementation2> {...}

So far so good. But there is one big trouble I see. Once I want to store a bunch of pointers to the interface to some container and want to access the instances of various implementation classes I face the trouble the Interface<T> is allways a different class by itself, not a single interface:

Interface<Implementation> and Interface<Implementation2> are different types.

Ok, let's make a common base class to derive the interfaces from...

template<typename T>
class Interface : public IfaceBase {
public:
  void doSomething() {
    static_cast<T&>(*this)._doSomething();
}

...but then I cannot access the final instance using the interface. It seems to me I am trying to create interface to interface which sounds crazy by itself anyway...

So I found CRTP not too usable in this case. I have searched the internet and have found MIXIN which seems to be a "CRTP turned upside down". But I am not sure whether it can be used for my purpose...

Could you please help me? If there is a way how to apply MIXINS or any other idiom/whatever to have C++ interfaces without virtuals, please share the idea :)

Many thanks in advance to anybody willing to help! Cheers Martin


Solution

  • I know two ways of calling non-virtual methods from different types in a polymorphic way:

    1. Type erasure: wraps non-virtual classes into others that have virtual methods (this is relatively close to what you attempted).
    2. Visitor pattern applied to variant types. This one requires all types to be known at compile time where the method is called.

    Since you don't want virtual methods at all, I'll only explain solution 2. If you're more interested about type erasure, C++ 'Type Erasure' Explained (Dave Kilian's blog) is a good read.

    Visitor pattern & variant types (C++17)

    Assuming you have types with non virtual methods:

    class Implementation1 {
        void doSomething() { /* ... */ }
    };
    
    class Implementation2 {
        void doSomething() { /* ... */ }
    };
    

    You can store any combinaison of them in a container using std::variant:

    // #include <variant>
    // #include <vector>
    using ImplVariant = std::variant<Implementation1,Implementation2>;
    std::vector<ImplVariant> array = {Implementation2(), Implementation1() /*, ...*/};
    

    To call doSomething on a MyVariant object, you apply a visitor to it. This is simply done in C++17 by passing a generic lambda to std::visit:

    for (auto& variant : array) {
        std::visit([](auto&& object) { object.doSomething(); }, variant);
    }
    

    Live demo

    Alternatively, you can make a variant of (smart) pointers.