Best way to declare an interface in C++11

C++InterfaceC++11PolymorphismAbstract

C++ Problem Overview


As we all know, some languages have the notion of interfaces. This is Java:

public interface Testable {
  void test();
}

How can I achieve this in C++ (or C++11) in most compact way and with little code noise? I'd appreciate a solution that wouldn't need a separate definition (let the header be sufficient). This is a very simple approach that even I find buggy ;-)

class Testable {
public:
  virtual void test() = 0;
protected:
  Testable();
  Testable(const Testable& that);
  Testable& operator= (const Testable& that);
  virtual ~Testable();
}

This is only the beginning.. and already longer that I'd want. How to improve it? Perhaps there is a base class somewhere in the std namespace made just for this?

C++ Solutions


Solution 1 - C++

For dynamic (runtime) polymorphism, I would recommend using the Non-Virtual-Interface (NVI) idiom. This pattern keeps the interface non-virtual and public, the destructor virtual and public, and the implementation pure virtual and private

class DynamicInterface
{
public:
    // non-virtual interface
    void fun() { do_fun(); } // equivalent to "this->do_fun()"

    // enable deletion of a Derived* through a Base*
    virtual ~DynamicInterface() = default;    
private:
    // pure virtual implementation
    virtual void do_fun() = 0; 
};

class DynamicImplementation
:
    public DynamicInterface
{
private:
    virtual void do_fun() { /* implementation here */ }
};

The nice thing about dynamic polymorphism is that you can -at runtime- pass any derived class where a pointer or reference to the interface base class is expected. The runtime system will automatically downcast the this pointer from its static base type to its dynamic derived type and call the corresponding implementation (typically happens through tables with pointers to virtual functions).

For static (compile-time polymorphism), I would recommend using the Curiously Recurring Template Pattern (CRTP). This is considerably more involved because the automatic down-casting from base to derived of dynamic polymporphism has to be done with static_cast. This static casting can be defined in a helper class that each static interface derives from

template<typename Derived>
class enable_down_cast
{
private:  
        typedef enable_down_cast Base;    
public:
        Derived const* self() const
        {
                // casting "down" the inheritance hierarchy
                return static_cast<Derived const*>(this);
        }

        Derived* self()
        {
                return static_cast<Derived*>(this);
        }    
protected:
        // disable deletion of Derived* through Base*
        // enable deletion of Base* through Derived*
        ~enable_down_cast() = default; // C++11 only, use ~enable_down_cast() {} in C++98
};

Then you define a static interface like this:

template<typename Impl>
class StaticInterface
:
    // enable static polymorphism
    public enable_down_cast< Impl >
{
private:
    // dependent name now in scope
    using enable_down_cast< Impl >::self;    
public:
    // interface
    void fun() { self()->do_fun(); }    
protected:
    // disable deletion of Derived* through Base*
    // enable deletion of Base* through Derived*
    ~StaticInterface() = default; // C++11 only, use ~IFooInterface() {} in C++98/03
};

and finally you make an implementation that derives from the interface with itself as parameter

class StaticImplementation
:
    public StaticInterface< StaticImplementation > 
{
private:
    // implementation
    friend class StaticInterface< StaticImplementation > ;
    void do_fun() { /* your implementation here */ }
};

This still allows you to have multiple implementations of the same interface, but you need to know at compile-time which implementation you are calling.

So when to use which form? Both forms will let you re-use a common interface and inject pre/post condition testing inside the interface class. The advantage of dynamic polymorphism is that you have runtime flexibility, but you pay for that in virtual function calls (typically a call through a function pointer, with little opportunity for inlining). Static polymporhism is the mirror of that: no virtual function call overhead, but the disadvantage is that you need more boilerplate code and you need to know what you are calling at compile-time. Basically an efficiency/flexiblity tradeoff.

NOTE: for compile-time polymporhism, you can also use template parameters. The difference between static interface through the CRTP idiom and ordinary template parameters is that CRTP-type interface are explicit (based on member functions), and template interface are implicit (based on valid expressions)

Solution 2 - C++

What about:

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

In C++ this makes no implications about copyability of child classes. All this says is that the child must implement test (which is exactly what you want for an interface). You can't instantiate this class so you don't have to worry about any implicit constructors as they can't ever be called directly as the parent interface type.

If you wish to enforce that child classes implement a destructor you can make that pure as well (but you still have to implement it in the interface).

Also note that if you don't need polymorphic destruction you can choose to make your destructor protected non-virtual instead.

Solution 3 - C++

According to Scott Meyers (Effective Modern C++): When declaring interface (or polymorphic base class) you need virtual destructor, for proper results of operations like delete or typeid on a derived class object accessed through a base class pointer or reference.

virtual ~Testable() = default;

However, a user-declared destructor suppresses generation of the move operations, so to support move operations you need to add:

Testable(Testable&&) = default; 
Testable& operator=(Testable&&) = default;

Declaring the move operations disables copy operations and you need also:

Testable(const Testable&) = default;
Testable& operator=(const Testable&) = default;

And the final result is:

class Testable 
{
public:
    virtual ~Testable() = default; // make dtor virtual
    Testable(Testable&&) = default;  // support moving
    Testable& operator=(Testable&&) = default;
    Testable(const Testable&) = default; // support copying
    Testable& operator=(const Testable&) = default;

    virtual void test() = 0;

};

Another interesting article here: The Rule of Zero in C++

Solution 4 - C++

By replacing the word class with struct, all of the methods will be public by default and you can save a line.

There's no need to make the constructor protected, since you can't instantiate a class with pure virtual methods anyway. This goes for the copy constructor as well. The compiler-generated default constructor will be empty since you don't have any data members, and is completely sufficient for your derived classes.

You're right to be concerned about the = operator since the compiler-generated one will certainly do the wrong thing. In practice nobody ever worries about it because copying one interface object to another never makes sense; it's not a mistake that happens commonly.

Destructors for an inheritable class should always be either public and virtual, or protected and non-virtual. I prefer public and virtual in this case.

The final result is only one line longer than the Java equivalent:

struct Testable {
    virtual void test() = 0;
    virtual ~Testable();
};

Solution 5 - C++

Keep in mind that the "rule of three" is unnecessary if you aren't managing pointers, handles, and/or all the data-members of the class have their own destructors that will manage any clean-up. Also in the case of a virtual base class, because the base class can never be directly instantiated, it's not necessary to declare a constructor if all you're wanting to-do is define an interface that has no data members ... the compiler defaults are just fine. The only item you would need to keep is the virtual destructor if you are planning on calling delete on a pointer of the interface type. So in reality your interface can be as simple as:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionemesxView Question on Stackoverflow
Solution 1 - C++TemplateRexView Answer on Stackoverflow
Solution 2 - C++Mark BView Answer on Stackoverflow
Solution 3 - C++AahzbgView Answer on Stackoverflow
Solution 4 - C++Mark RansomView Answer on Stackoverflow
Solution 5 - C++JasonView Answer on Stackoverflow