Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to declare an interface in C++11

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?

like image 379
emesx Avatar asked Jan 14 '13 17:01

emesx


People also ask

How do you declare an interface class?

To declare a class that implements an interface, you include an implements clause in the class declaration. Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class.

Which of the following is correct declaration of interface?

An interface is declared by using the interface keyword. It provides total abstraction; means all the methods in an interface are declared with the empty body, and all the fields are public, static and final by default. A class that implements an interface must implement all the methods declared in the interface.


2 Answers

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)

like image 140
TemplateRex Avatar answered Oct 18 '22 02:10

TemplateRex


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.

like image 40
Mark B Avatar answered Oct 18 '22 03:10

Mark B