45

Since C++ lacks the interface feature of Java and C#, what is the preferred way to simulate interfaces in C++ classes? My guess would be multiple inheritance of abstract classes. What are the implications in terms of memory overhead/performance? Are there any naming conventions for such simulated interfaces, such as SerializableInterface?

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
Tony the Pony
  • 37,471
  • 63
  • 170
  • 273
  • 12
    Lacks interface. That seems like a negative wording. C++ does not lack interfaces (the class is an interface) it just lacks the keyword interface because it has not been stunted. – Martin York Aug 01 '09 at 17:35
  • 7
    The Interface keyword is guaranteed not to contain code or data so they will easily interact with other interfaces without problems. There is no way to make such a guarantee in C++, you just have to hope they don't do anything that conflicts. A lot of stuff that Java and C# do for code readability, interoperability and understandability were figured out in response to problems people encountered while working in C++. – Bill K Aug 01 '09 at 19:26
  • 2
    possible duplicate of [How do you declare an interface in C++?](http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c) – Christophe Weis Aug 26 '15 at 06:04

9 Answers9

46

Since C++ has multiple inheritance unlike C# and Java, yes you can make a series of abstract classes.

As for convention, it is up to you; however, I like to precede the class names with an I.

class IStringNotifier
{
public:
  virtual void sendMessage(std::string &strMessage) = 0;
  virtual ~IStringNotifier() { }
};

The performance is nothing to worry about in terms of comparison between C# and Java. Basically you will just have the overhead of having a lookup table for your functions or a vtable just like any sort of inheritance with virtual methods would have given.

Craig McQueen
  • 37,399
  • 27
  • 113
  • 172
Brian R. Bondy
  • 314,085
  • 114
  • 576
  • 619
13

There's really no need to 'simulate' anything as it is not that C++ is missing anything that Java can do with interfaces.

From a C++ pointer of view, Java makes an "artificial" disctinction between an interface and a class. An interface is just a class all of whose methods are abstract and which cannot contain any data members.

Java makes this restriction as it does not allow unconstrained multiple inheritance, but it does allow a class to implement multiple interfaces.

In C++, a class is a class and an interface is a class. extends is achieved by public inheritance and implements is also achieved by public inheritance.

Inheriting from multiple non-interface classes can result in extra complications but can be useful in some situations. If you restrict yourself to only inheriting classes from at most one non-interface class and any number of completely abstract classes then you aren't going to encounter any other difficulties than you would have in Java (other C++ / Java differences excepted).

In terms of memory and overhead costs, if you are re-creating a Java style class hierarchy then you have probably already paid the virtual function cost on your classes in any case. Given that you are using different runtime environments anyway, there's not going to be any fundamental difference in overhead between the two in terms of cost of the different inheritance models.

CB Bailey
  • 648,528
  • 94
  • 608
  • 638
7

"What are the implications in terms of memory overhead/performance?"

Usually none except those of using virtual calls at all, although nothing much is guaranteed by the standard in terms of performance.

On memory overhead, the "empty base class" optimization explicitly permits the compiler to layout structures such that adding a base class which has no data members does not increase the size of your objects. I think you're unlikely to have to deal with a compiler which does not do this, but I could be wrong.

Adding the first virtual member function to a class usually increases objects by the size of a pointer, compared with if they had no virtual member functions. Adding further virtual member functions makes no additional difference. Adding virtual base classes might make a further difference, but you don't need that for what you're talking about.

Adding multiple base classes with virtual member functions probably means that in effect you only get the empty base class optimisation once, because in a typical implementation the object will need multiple vtable pointers. So if you need multiple interfaces on each class, you may be adding to the size of the objects.

On performance, a virtual function call has a tiny bit more overhead than a non-virtual function call, and more importantly you can assume that it generally (always?) won't be inlined. Adding an empty base class doesn't usually add any code to construction or destruction, because the empty base constructor and destructor can be inlined into the derived class constructor/destructor code.

There are tricks you can use to avoid virtual functions if you want explicit interfaces, but you don't need dynamic polymorphism. However, if you're trying to emulate Java then I assume that's not the case.

Example code:

#include <iostream>

// A is an interface
struct A {
    virtual ~A() {};
    virtual int a(int) = 0;
};

// B is an interface
struct B {
    virtual ~B() {};
    virtual int b(int) = 0;
};

// C has no interfaces, but does have a virtual member function
struct C {
    ~C() {}
    int c;
    virtual int getc(int) { return c; }
};

// D has one interface
struct D : public A {
    ~D() {}
    int d;
    int a(int) { return d; }
};

// E has two interfaces
struct E : public A, public B{
    ~E() {}
    int e;
    int a(int) { return e; }
    int b(int) { return e; }
};

int main() {
    E e; D d; C c;
    std::cout << "A : " << sizeof(A) << "\n";
    std::cout << "B : " << sizeof(B) << "\n";
    std::cout << "C : " << sizeof(C) << "\n";
    std::cout << "D : " << sizeof(D) << "\n";
    std::cout << "E : " << sizeof(E) << "\n";
}

Output (GCC on a 32bit platform):

A : 4
B : 4
C : 8
D : 8
E : 12
Steve Jessop
  • 257,525
  • 32
  • 431
  • 672
6

Interfaces in C++ are classes which have only pure virtual functions. E.g. :

class ISerializable
{
public:
    virtual ~ISerializable() = 0;
    virtual void  serialize( stream& target ) = 0;
};

This is not a simulated interface, it is an interface like the ones in Java, but does not carry the drawbacks.

E.g. you can add methods and members without negative consequences :

class ISerializable
{
public:
    virtual ~ISerializable() = 0;
    virtual void  serialize( stream& target ) = 0;
protected:
    void  serialize_atomic( int i, stream& t );
    bool  serialized;
};

To the naming conventions ... there are no real naming conventions defined in the C++ language. So choose the one in your environment.

The overhead is 1 static table and in derived classes which did not yet have virtual functions, a pointer to the static table.

Christopher
  • 8,656
  • 3
  • 30
  • 37
  • 1
    I do not think you can have virtual constructors. You can have virtual destructors, though. – jkeys Aug 01 '09 at 15:12
  • 2
    I see no reason for destructor being pure virtual, just plain virtual would be enough. Also declaring dtor is not enough, it has to be defined. In case of pure virtual dtor it has to be defined outside the class definition, like this: ISerializable::~ISerializable() { } because C++ grammar doesn't allow for both pure virtual specifier and in-class member function definition. – robson3.14 Aug 02 '09 at 18:09
3

In C++ we can go further than the plain behaviour-less interfaces of Java & co. We can add explicit contracts (as in Design by Contract) with the NVI pattern.

struct Contract1 : noncopyable
{
    virtual ~Contract1();
    Res f(Param p) {
        assert(f_precondition(p) && "C1::f precondition failed");
        const Res r = do_f(p);
        assert(f_postcondition(p,r) && "C1::f postcondition failed");
        return r;
    }
private:
    virtual Res do_f(Param p) = 0;
};

struct Concrete : virtual Contract1, virtual Contract2
{
    ...
};
Luc Hermitte
  • 29,719
  • 7
  • 60
  • 74
2

Interfaces in C++ can also occur statically, by documenting the requirements on template type parameters.

Templates pattern match syntax, so you don't have to specify up front that a particular type implements a particular interface, so long as it has the right members. This is in contrast to Java's <? extends Interface> or C#'s where T : IInterface style constraints, which require the substituted type to know about (I)Interface.

A great example of this is the Iterator family, which are implemented by, among other things, pointers.

Caleth
  • 35,377
  • 2
  • 31
  • 53
1

If you don't use virtual inheritance, the overhead should be no worse than regular inheritance with at least one virtual function. Each abstract class inheritted from will add a pointer to each object.

However, if you do something like the Empty Base Class Optimization, you can minimize that:

struct A
{
    void func1() = 0;
};

struct B: A
{
    void func2() = 0;
};

struct C: B
{
    int i;
};

The size of C will be two words.

keraba
  • 544
  • 2
  • 9
1

By the way MSVC 2008 has __interface keyword.

A Visual C++ interface can be defined as follows: 

 - Can inherit from zero or more base
   interfaces.
 - Cannot inherit from a base class.
 - Can only contain public, pure virtual
   methods.
 - Cannot contain constructors,
   destructors, or operators.
 - Cannot contain static methods.
 - Cannot contain data members;
   properties are allowed.

This feature is Microsoft Specific. Caution: __interface has no virtual destructor that is required if you delete objects by its interface pointers.

Sergey Podobry
  • 6,627
  • 1
  • 37
  • 47
0

There is no good way to implement an interface the way you're asking. The problem with an approach such as as completely abstract ISerializable base class lies in the way that C++ implements multiple inheritance. Consider the following:

class Base
{
};
class ISerializable
{
  public:
    virtual string toSerial() = 0;
    virtual void fromSerial(const string& s) = 0;
};

class Subclass : public Base, public ISerializable
{
};

void someFunc(fstream& out, const ISerializable& o)
{
    out << o.toSerial();
}

Clearly the intent is for the function toSerial() to serialize all of the members of Subclass including those that it inherits from Base class. The problem is that there is no path from ISerializable to Base. You can see this graphically if you execute the following:

void fn(Base& b)
{
    cout << (void*)&b << endl;
}
void fn(ISerializable& i)
{
    cout << (void*)&i << endl;
}

void someFunc(Subclass& s)
{
    fn(s);
    fn(s);
}

The value output by the first call is not the same as the value output by the second call. Even though a reference to s is passed in both cases, the compiler adjusts the address passed to match the proper base class type.