tutorial - what is an interface class c++




Best way to declare an interface in C++11 (4)

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;

};

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?


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();
};

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();
}

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.





abstract