views:

185

answers:

9

I read a lot about "program to interfaces" and "inversion of control" during the last days. Mostly in the context with the Java language. My question is if it is also a common practice in C++ development. What are the advantages? What are the disadvantages?

Is it worth to apply to small projects (like 15-20 classes)?

+4  A: 

Absolutely! Encapsulation is a major part of OOP philosophy. By keeping the implementation separate from the interface of a class, your code becomes so much more versatile. For example, if I had a 'Vector' class, and I wanted to change the internal representation from an x and y pair to a length and direction (lets say it is for efficiency), then only changing a few member functions that handle the implementation is FAR easier than scouring through 100 source files for every class that is dependent on the classes implementation.

And yes, small projects could benefit as well. This concept is also useful when you have multiple classes that do the same thing (say rendering) but in a different way (perhaps for different platforms). By giving them all the same interface (or in C++, deriving them all from the same base class), then any object can switch between them with a simple substitution.

Alexander Rafferty
Your answer isn't incorrect, but I don't think it captures the full intent of the question. For example how would you mock a Vector class for testing?
Mark Ransom
A: 

Well, "program to interfaces" is used by anyone in any language that writes libraries.

A library user would not want the library interface changing all the time. Imagine if you had to rewrite your programs because the C library authors decided to redefine "printf". Or what if Java library decided to redefine the interface of toString?

So yes, "program to interfaces" is used in C++.

Zan Lynx
+1  A: 

I think there may be some confusion about terminology, since "interface" isn't a term defined by the C++ language. In the context of your question you obviously mean an abstract class specification which can be implemented by one or more concrete classes.

I wouldn't say it's common, but it's not uncommon either - maybe somewhere in between? Microsoft's COM is built on the concept.

See this question for more information about how it's done: http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c

Mark Ransom
+4  A: 

The principles you speak of are generally applicable to any OO language. The basic tenet here is "loose coupling". A class that depends upon another class (contains an instance of it and calls methods on it as part of its own work) really only depends on a set of functionality the dependency provides. If the class defines a reference to a concrete class that it depends on, and you then want to replace the class with another, you not only have to develop the new class, but change the dependent class to depend on the new type. This is generally bad, because if your class is depended on by many other classes, you have to change code in multiple places, requiring you to test all the use cases involving those objects to ensure you haven't broken previously-working functionality.

Interfaces were designed to eliminate this, allowing multiple classes that are unrelated by ancestry to be used interchangeably based on a common, enforced set of methods that you know a class will implement. If, instead of depending on a class, you depended on an interface, any class implementing the interface would fulfill the dependency. That allows you to write a new class to replace an old one, without the class that uses it knowing the difference. All you have to modify is the code that creates the concrete implementation of the class filling the dependency.

This presents a quandary; sure, your class Depender can say it needs an IDoSomething instead of a DoerClass, but if Depender knows how to create a DoerClass to use as the IDoSomething, you haven't gained anything; if you want to replace DoerClass with BetterDoer, you must still change Depender's code. The solution is to give the responsibility for giving the class an instance of a dependency to a third party, a Creator. The class chosen for this depends on the context. If a class naturally has both Depender and DoerClass, it's the obvious choice to use to put them together. This is often the case when you have one class that has two helper dependencies, and one dependency needs the other as well. Other times you may create a Factory, which exists to provide the caller with an instance of a specific object, preferably with all dependencies hooked up.

If you have several interdependent classes, or dependencies many levels deep, you may consider an IoC framework. IoC containers are to Factories as Repositories are to DAOs; they know how to get you a fully-hydrated instance of ANY class requiring one or more dependencies, like a Repository can produce any fully-hydrated domain object from data in the DB. It does this by being told what concrete class should be used to fill a dependency in a certain situation, and when asked to provide a class, it will instantiate that class, providing instances of the required dependencies (and dependencies of dependencies). This can allow patterns where Class A depends on B, which depends on C, but A cannot know about C. The IoC framework knows about all three, and will instantiate a B, give it a new C, then give the B to a new A.

KeithS
Great explanation.
mbeckish
It's only half the story though, in that it doesn't explain what might be the most common way in which people "program to an interface" in C++: through templates and static polymorphism.
jalf
So it is recommended for every class I introduce I write a interface/abstract base class even if I do not see any need for another implementation (yet)?
Benjamin
@Benjamin: It is recommended by SOLID practices. GRASP would have you do the same IF you foresaw a need, and to refactor if an unforeseen need came about. There are tools available that make refactoring in these situations easier.
KeithS
+1  A: 

There's more to interfaces in C++ than in Java. The simple answer is yes, it is a common practice. Whether you should follow it in your small project depends on the case. Judge for each class, not for the project as a whole. As a general rule, if it's not broken don't fix it.

That said, in C++ you have two kinds of interfaces: that which supports runtime polymorphism and that which supports compile-time polymorphism. The runtime polymorphism is very similar to what you know from Java. The compile-time polymorphism comes from the use of templates.

The advantage of runtime polymorphism is that it usually results in a small binary, and it makes it easier for the compiler to produce meaningful error messages at compile-time. On the down side it also results in a slightly slower binary, because calls require one more dereference.

The advantage of compile-time polymorphism is that often your source is smaller, and the calls' runtime is optimized to as fast as it gets. On the other hand because the compiler needs to do more work compile-time tends to be slower. Often the compile-time becomes significantly slower, because templates are usually defined in header files, thus recompiled again and again for each compilation unit that depends on them.

wilhelmtell
A: 

Interfaces became popular with Java, and currently with C#, before interfaces Object Oriented Programming already exists, the most complete language ever created (in my opinion) C++ did not grow up on the basis of interfaces. The primary need for creating interfaces came for solving the problem of multiple inheritance (c++ allow multiple inheritance), so that interfaces define only signatures that some class must implement in modern OO languages.

In C++ it is not an extended practice to define interfaces (which really are *pure abstract classe*s). But there is a common practice to define a file containing declarations (.H) and other containing implementation (.CPP), probably it was an inspiration for creating interfaces.

ArceBrito
+1  A: 

I'd say that these concepts extend well beyond simply OO but are equally applicable to most, if not all, of the paradigms you might use in C++ including Generic Programming.

Noah Roberts
+2  A: 

Yes, it is fairly common, but not in the form you might expect.

In Java, the interface is formalized and explicit, and programming to an interface means implementing that specific interface.

In C++, the same is done too, sometimes (although using abstract base classes rather than interfaces), but another common way it is done in C++ is with templates, where the interface is implicit.

For example, the standard library algorithms all work with the iterator "interface", except that no such interface is ever defined in code. It is a convention, and nothing more.

A valid iterator is required to expose certain functionality, and so, any type which exposes this functionality is an iterator. But it doesn't have to implement some kind of hypothetical IIterator interface like you would in Java.

The same is common in user code. You often write your code to accept a template parameter which might be anything that works. You implicitly define an interface through your use of the type: anything you require from it becomes part of this implicit interface that a type must satisfy in order to be usable.

The interface is never formalized in code, but you are still using it and programming against it.

jalf
A: 

Have a look a the design of the standard template library. For example msdn channel9 has some nice video tutorials, which explain the design (and MSFTs implementation) of the STL.

http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Introduction-to-STL-with-Stephan-T-Lavavej

Nils