Using Interfaces in C++

Abstract

The distinction between classes and interfaces is a powerful language feature present both in Java and C# (along with many other languages) but not in C++. For years, our team has been using a “methodological” implementation of the interface concept for C++, which I present here. Starting in VS7, there’s also an MS extension pointing the same way, allowing the compiler to enforce most of the defining characteristics of an interface, and of course, managed extensions for C++ supports the definition and implementation of .NET interfaces too. However, there are some subtle and not so subtle differences between each of these mechanisms that you should take into account.

Background

An interface describes the behavior or capabilities of a class without committing to a particular implementation. It represents a contract between a provider and its users, defining what’s required from each implementer, but only in terms of the services they must provide, no matter how they manage to do it.

In case you are unfamiliar with the concept of interfaces, and when and how to use it to improve your design, the following MSDN article might be of great help. It’s addressed to Visual Basic users switching to VB.NET, but it does a very good job of explaining the basic ideas that apply to any object-oriented language anyway.

Introduction

Many years ago, around November 1999, I defined a way to declare interfaces for C++, and to make classes implement them, just by using a few macros and making sure some basic rules were followed. I should make it clear that I don’t claim to be the “inventor” of this technique or anything like that. Although it was independently developed, mostly with the invaluable advice of Roberto Lublinerman, I later found many articles on the Internet that described more or less the same ideas, and at least some of them were dated way before we had even come to think about it.

These days, the solution can be improved by making use of Microsoft extensions that were introduced in later versions of the C++ compiler, but let me go one step at a time.

The First Version

First, some macros are defined in a header file that you’ll probably want to include in your precompiled headers:


//
// CppInterfaces.h
//

#define Interface class

#define DeclareInterface(name) Interface name {
public:
virtual ~name() {}

#define DeclareBasedInterface(name, base) class name :
public base {
public:
virtual ~name() {}

#define EndInterface };

#define implements public

By using these macros, you can declare an interface in the following way:


//
// IBar.h
//

DeclareInterface(IBar)
virtual int GetBarData() const = 0;
virtual void SetBarData(int nData) = 0;
EndInterface

Then, you can declare a class that implements this interface with something like the following:


//
// Foo.h
//

#include “BasicFoo.h”
#include “IBar.h”

class Foo : public BasicFoo, implements IBar
{
// Construction & Destruction
public:
Foo(int x) : BasicFoo(x)
{
}

~Foo();

// IBar implementation
public:
virtual int GetBarData() const
{
// stuff…
}

virtual void SetBarData(int nData)
{
// stuff…
}
};

Easy, isn’t it? Without much effort, you now are able to use interfaces in C++. However, because they aren’t directly supported in the language, you are supposed to follow some rules that can’t be automatically enforced at compilation time. After all, all that the compiler can see is the use of plain old multiple inheritance and abstract base classes. Here are the rules you need to follow, along with some recommendations:


  • When declaring a class, use the first base class for “structural” inheritance (the “is a” relationship) if there is one, as you normally do. (For example: CFrameWnd derives from CWnd, CBitmapButton derives from CButton, YourDialog derives from CDialog, and so on.) This is especially important if you are deriving from MFC classes; declaring them as the first base class avoids breaking MFC’s RuntimeClass mechanism.

  • Use additional base classes for interface implementation, as many as you want or need. (For example: class Foo : public BasicFoo, implements IBar, implements IOther, implements IWhatever, …)

  • Do not declare any member variables inside the interfaces. Interfaces are intended to express behavior, not data. Besides, this helps to avoid some problems if you were to use multiple “structural” inheritance and happened to be deriving more than once from the same interface.

  • Declare all the member functions in the interfaces as virtual pure (in other words, with “= 0”). This ensures every instantiable class that declares to implement an interface does it for all its functions. It’s okay to partially implement an interface in an abstract class (in fact, it will be abstract anyway if you do so) as long as you implement the remaining functions in the derived classes you actually intend to instantiate. Because the interfaces offer no “basic” implementation, you need to be sure everyone that receives a pointer to some interface will be able to call any of its members; declaring all your interface members as virtual pure will enforce this at compile time.

  • Do not derive your interfaces from anything but other interfaces. You can use the DeclareBasedInterface() macro for that. Normal classes can choose to implement the basic interface or the derived (extended) one; the latter of course means implementing both.

  • Assigning a pointer to a class that implements some interface to a pointer to that interface requires no casting, because you will be actually casting to a base class. Doing it the other way though (from an interface pointer to a pointer to the class implementing it), will require an explicit cast, as you will be casting to a derived class. Because you will in fact be using multiple inheritance (even if for virtually every other practical need, you can think of it as single inheritance plus interface implementations), these casts can’t be done the “old” way because they may need different actual memory values. However, enabling Run-Time Type Information (/GR compiler option) and using dynamic casts works fine and it’s of course safer anyway.

  • Further, the use of dynamic_cast will give you a way to ask any object or interface whether it implements a given interface or not.

  • You need to be careful to avoid name conflicts between functions in different interfaces because it isn’t easy to detect and resolve those conflicts should you have a class implementing both.

Evaluation

When I posted about the above technique in my recently created blog, one of the readers expressed some concerns in the following terms:


  • Why bother with the macros? They don’t enforce anything, and they don’t improve readability any more than these old standbys:

  • #define begin {
    #define end }

  • Maybe that’s useful as a crutch for Java/C# developers, but if a developer needs a crutch like this, they have other problems.

If you look closely at the DeclareInterface and DeclareBasedInterface macros, you’ll note that there is at least something that is being enforced there: Every class implementing an interface will have a virtual destructor. You may or may not think this is important, but there are cases when the lack of a virtual destructor will cause problems. Consider the following code, for instance:


DeclareInterface(IBar)
virtual LPCTSTR GetName() const = 0;
virtual void SetName(LPCTSTR name) = 0;
EndInterface

class Foo : implements IBar
{
// Internal data
private:
char* m_pName;

// Construction & Destruction
public:
Foo()
{
m_pName = NULL;
}

~Foo()
{
ReleaseName();
}

// Helpers
protected:
void ReleaseName()
{

if (m_pName != NULL)
free(m_pName);
}

// IBar implementation
public:
virtual const char* GetName() const
{
return m_pName
}

virtual void SetName(const char* name)
{
ReleaseName();
m_pName = _strdup(name);
}
};

class BarFactory
{
public:
enum BarType {Faa, Fee, Fii, Foo, Fuu};

static IBar CreateNewBar(BarType barType)
{
switch (barType)
{
default:
case Faa:
return new Faa;
case Fee:
return new Fee;
case Fii:
return new Fii;
case Foo:
return new Foo;
case Fuu:
return new Fuu;
}
}
};

As you can see, there’s a factory to which you can ask to create an IBar implementation, depending on a BarType parameter. After using it, you are expected to delete the object; so far, so good. Now, consider how this is used in the main function of some application:


int main()
{
IBar* pBar = BarFactory::CreateBar(Foo);

pBar->SetName(“MyFooBar”);
// Use pBar as much as you want,
// …

// and then just delete it when it’s no longer needed
delete pBar; // Oops!
}

What happens at the delete pBar line depends on whether the actual class of that object has a virtual destructor or not. If Foo doesn’t have a virtual destructor, the compiler will only generate a call to IBar‘s implicit empty destructor; the destructor for Foo won’t be called, and thus you’ll have a memory leak. The virtual destructors in the interface declaration macros are there to avoid this situation; they ensure every class implementing an interface will also have a virtual destructor.

Now, if you are going to use DeclareInterface, it kind of makes sense to also use EndInterface to match with it, rather than a closing brace with no apparent opening one to match. The need for the Interface and implements macros, which resolve to class and public, respectively, could be objected as superfluous, but I find them to better express the actual intent of the code. If I write Foo : public IBar, you can only read some inheritance there and nothing else. If on the other hand, I write Foo implements IBar, you can see it for its actual value and intent: the implementation of the interface concept, and not just any kind of class inheritance. I do find value in that.

To be fair, I’m sure that the reader was actually concerned with the other things these macros do not and cannot enforce: interfaces are expected to have only pure virtual functions and no instance data. But, at least, if you write your interfaces using DeclareInterface and EndInterface, the inclusion of any instance data or non virtual pure function should be easy to spot. In Joel Spolsky’s words, these macros also help by “making wrong code look wrong”.

C++ Interfaces Support in VS7

The folks at Microsoft must have felt the same need to enforce those restrictions on classes used as interfaces, judging from the introduction in VS7 of the __interface keyword as a new Microsoft extension to the C++ compiler. In the documentation, they define a Visual C++ interface as follows:


  • Can inherit from zero or more base interfaces.

  • Cannot inherit from a base class.

  • Can only contain public and pure virtual methods.

  • Cannot contain constructors, destructors, or operators.

  • Cannot contain static methods.

  • Cannot contain data members; properties are allowed.

And they note: “A C++ class or struct could be implemented with these rules, but __interface enforces them.” So, if you are not worried by portability, you could use this extension and have the compiler enforce what needs to be enforced, right? Wrong.

Remember that bit about the need for virtual destructors? __interface does not add a virtual destructor for the implementing class, and I can understand why MS didn’t see the need for virtual destructors in interfaces. If you look at the samples in the documentation, it’s pretty clear from where they are COMing. They obviously created this extension with COM interfaces in mind and you never use delete with them because they are count-referenced objects that call delete on themselves when the count reaches zero.

Couldn’t you just use __interface in the DeclareInterface macro definition, to have the best of both worlds? Hmm…, read the definition again: “…cannot contain constructors, destructors, or operators.” This led me to initially think it wasn’t possible, and even to say that while __interface might be useful for COM interfaces, it was neither intended nor suitable for the general purpose interfaces you are learning about here. Fortunately, that’s not the end of the story.

The Best of Both Worlds

A while later, I found a rather simple solution: the name for the desired interface is actually used to declare a class that contains a virtual destructor and inherits from an __interface that contains the needed methods. The macros are now defined as follows:


//
// CppInterfaces2.h
//

#define Interface class

#define implements public

#define DeclareInterface(name) __interface actual_##name {

#define DeclareBasedInterface(name, base)
__interface actual_##name
: public actual_##base {

#define EndInterface(name) };
Interface name : public actual_##name {
public:
virtual ~name() {}
};

Here is how you declare an interface using the above-defined macros:


//
// IBar2.h
//

DeclareInterface(IBar)
int GetBarData() const;
void SetBarData(int nData);
EndInterface(IBar)

As you may have noticed, these new macro definitions require using the name of the wanted interface (in other words, IBar) twice, first for DeclareInterface(), and then for EndInterface(). This introduces an always undesired redundancy, which made me struggle for a while trying to eliminate, but failed. If anyone finds a way to define the macros to avoid requiring the same name twice, please let me know.

On the other hand, provided you don’t mind sacrificing portability to anything but MS compilers starting from VS7, the new macros have many advantages over their predecessors, simply because every requirement for an interface (only pure virtual methods, no data members, and virtual destructor for implementing classes) is now automatically enforced. You don’t even need to explicitly declare interface methods as virtual or pure virtual (“= 0”), although the compiler won’t complain if you do so.

Additional Reading

Before closing this article, I’d like to include some links to related resources that I found while doing research on this topic.

The techniques described here allow defining and implementing interfaces in C++ through the use of abstract base classes. Some people don’t like this as a solution because it forces every implementing class to have (and use) a virtual table and they find this unacceptable due to the space (the virtual table for each class) and performance (the indirection in each method call) penalties it imposes. As an alternative, Brian McNamara and Yannis Smaragdakis from the Georgia Institute of Technology wrote a paper Static interfaces in C++, which was published in the First Workshop on C++ Template Programming, Erfurt, Germany, October 10 2000.

Christopher Diggins wrote a proposal for a modification of the C++ language, to make it support interfaces without virtual functions. I have no idea whether this proposal was actually presented or considered by the standards committee.

Dr. Dobb’s Journal, August 1998, includes an article by Fred Wild, “Keeping interfaces and implementations separate,” which discusses some ways to do so in C++ code.

Nemanja Trifunovic pointed me to another alternative for static interfaces, the Boost Interface Library.

There’s a very interesting interview with Scott Meyers, by Bill Venners on December 2002, in which they discuss the topic of interfaces in C++.

Last, but not least, the father of C++, Bjarne Stroustrup himself, made interesting comments about interfaces and C++ in an interview by Bill Venners on November 2003.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read