According to Herb Sutter one should prefer abstract interfaces (all pure virtual functions) to abstract classes in C++ to decouple the implementation as far as possible. While I personally find this rule very useful, I have recently joined a team with many Java programmers and in the Java code this guideline does not seem to exist. Functions and their implementations are very frequently located in abstract classes. So did I get Herb Sutter all wrong even for C++ or is there a general difference in the usage of abstract functions in C++ compared to Java. Are abstract classes with implementation code more sensible in Java than in C++ and if yes why ?
-
1I had some doubts and finally put it here because it could be due to some design principles that I'm missing about the java oo. So then it is not about a general advice but more about the right and the wrong to use the language– MartinCommented Aug 7, 2012 at 20:54
-
Interfaces are meant to be purely virtual. The idea of abstract classes is that they are partially implemented, and it's up to the implementation to fill in the gaps without repeating code unnecessarily (for example, why have write(byte) and write(int) in every subclass when you can have the abstract class call write(byte) from write(int))– Ryan AmosCommented Aug 7, 2012 at 20:57
-
1Possibly related: stackoverflow.com/q/1231985/484230 gives a reason the prefer abstract classes in java. For C++ this reason does not seem to hold true due to the existance of free functions that can add functionality at the interface level– MartinCommented Aug 7, 2012 at 21:09
-
1I think the Golden Rule is to "make non-leaf classes abstract", but that doesn't make any "only pure" or "empty" requirements.– Kerrek SBCommented Aug 7, 2012 at 21:13
-
1If it works for you it works for you. I really don't see why people panic once their code no longer adheres to the latest opinions.– JamesCommented Aug 8, 2012 at 15:19
4 Answers
OOP has composition and substitution.
C++ has multiple inheritance, template specialisation, embedding and value/move/pointer semantics.
Java has single inheritance and interfaces, embedding and reference semantics.
The common way the OOP school uses these languages is to employ inheritance for object substitution and embedding for composition. But you also need a common ancestor and a way to runtime-cast (in C++ is called dynamic_cast
, in Java is just asking an interface from another).
Java does all this by its own java.lang.Object
rooted hierachy. C++ doesn't have a predefined common root, so you should at least define it, to come to a same "picture" (but this is limiting some C++ possibilities...).
After that, the possibility to have compile-time polymorphism (think to CRTP) and value semantic can offer also other alternatives to the way the concept of "OOP object" can be ported into a C++ program.
You can even imagine the heresy to use embedding and implicit conversion to manage substitution and private inheritance to manage composition, in fact inverting the traditional school paradigm. (Of course, this way is 20 years younger than the other, so don't expect a wide community support in doing that)
Or you can imagine a virtual common base to all classes, form interface (no implementation) to final classes (fully implemented) going through partially implemented interfaces an even interface clusters, using "dominance" as dispatching from interface to implementations through a "multi stacked-parallelogram" inheritance scheme.
Comparing OOP to java to C++ assuming there is just one and only OOP way is limiting the capabilities of both the languages.
Forcing C++ to strictly adhere to Java coding idioms is denaturating C++ as forcing Java to behave as a C++-like language is denaturating Java.
Is not a matter of "sensibility" but of different "aggregation mechanisms" the two languages have and different way to combine them that makes some idiom more profitable in one language than the other and vice versa.
-
1I think this answer is very interesting, since it succintly describes language features as a tool for oo and design principles only as a help and not a doctrine. However you do not need a common root if you want to do oo in c++. This is simply wrong, also for the fact that you have operators and templates (which are a very powerful alternative to the main tree design of java as you also pointed out). Apart from that your points are the most worthwhile in all answers– MartinCommented Aug 9, 2012 at 21:31
-
1@Martin: In "technical sense" you're right, but if you need runtime polymorophism (because the actual type of the instantiated objects depends on program input) a "root" ('a' is an article, not a shortcut for "one and only") is what makes all object "cousins", and the hierarchy run-time-walkable. Different roots originate different ancestries not each-other related. Whether this is "good" or "bad" is a matter of context, not idiom. Commented Aug 10, 2012 at 6:44
-
That's true. I thought you were referring to artificially porviding one general root for an entire c++ program and saw it as defect that it is not present, compared to java. But after your edit you make the point quite clear. Thanks again– MartinCommented Aug 10, 2012 at 8:33
The principle holds for both languages, but you're not doing a fair comparison. You should compare C++ pure abstract classes with Java interfaces.
Even in C++, you can have abstract classes that have some of the functions implemented, but derive from a pure abstract class (no implementations). In Java, you'd have the same abstract classes (with some implementations), that can derive from interfaces (no implementations).
-
So when would you prefer an abstract class over an interface class in c++. I always opted for interface plus non-member functions in c++.– MartinCommented Aug 7, 2012 at 20:57
-
1@Martin that depends on the design. Basically, always prefer an interface. But "always" rules have exceptions... Commented Aug 7, 2012 at 20:59
-
True enough but in the Java Code I'm seeing abstract classes largely representing the majority. Could this be due to the fact that free functions working on interfaces are not possible in java ?– MartinCommented Aug 7, 2012 at 21:01
-
3@Martin well free functions are not at all possible in Java, so that might be a reason, yes. Good spot! Answered your own question! You can add an answer yourself, I think that's it. Commented Aug 7, 2012 at 21:03
Generally the same OO principles hold true for Java and C++. However, one big difference is that C++ supports multiple-inheritance while in Java you can only inherit from one class. This is the main reason why Java has interfaces I believe, to supplement for the lack of multiple inheritance and probably to restrict what you can do with it (since there is a lot of criticism over the abuse of multiple inheritance). So, probably in a Java programmers mind, there is a stronger distinction between abstract classes and interfaces. Abstract classes are used to share and inherit behavior while interfaces are simply used to add extra functionality. Remember, in Java you can inherit from only one class, but you can have many interfaces. In C++ however, pure abstract classes (i.e. a "C++ interface") are used to share and inherit behavior unlike the purpose of a Java interface (although you are still required to implement the functions), hence the usage is different from Java interfaces.
Sometimes it makes sense to have some default implementation. For example a generic PrintError(string msg) method that is applicable to all sub classes.
virtual PrintError(string msg) { cout << msg; }
It can still be overridden if really required, but you can save the client some hassle by allowing them just call the generic version.