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 ?
|
migrated from stackoverflow.com Aug 8 '12 at 1:43
This question came from our site for professional and enthusiast programmers.
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 Java does all this by its own 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. |
|||||||||||||
|
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). |
|||||||||||||||||
|
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.
It can still be overridden if really required, but you can save the client some hassle by allowing them just call the generic version. |
|||
|