Many people seem to think that C++ is much more difficult than, let's say, Java. Although I agree that some things are sugar-coated in Java, I feel the general difficulty is practically the same. Then why is C++ perceived hard to learn, you ask ? Well, C++ does not only mix two programming languages, but two programming paradigms as well. Both procedural programming and object oriented programming are viable solutions to problems implemented in C++. To further illustrate this point, I provide a bit of history.
C++ was designed with an important feature in mind: backward compatibility with C. Because of this, many experienced C programmers jumped on the C++ bandwagon, using the new features as seen fit. This created a weird version of pure C++ because developers used object oriented features in a procedural way. This was not really seen as a problem because, after all, C++ was designed to do just that. The problem is that this complicates matters a lot, requiring new C++ students to learn the way of thinking of both C and C++, complicated by subtle language differences.
New students should therefore choose between pure C and pure C++ and stick to it. But is this practically possible, as some API's are C oriented and some C++ oriented ? I think that C programmers will have less problems with this, because most API's, C or C++ oriented, originated in C. It is true that a lot of C++ API's are merely wrappers around C API's. This isn't necessarily a problem, except when you are a C++ purist and can't find a good C++ oriented API for the particular thing you're trying to do.
But the future looks bright with quality object oriented API's like TrollTech's QT (http://www.trolltech.com) and the ACE networking API (http://www.cs.wustl.edu/~schmidt/ACE.html), both great choices for C++ purists.
DISCLAIMER: Altough I like pure C++ better than pure C, I am not implying pure C is inferior to pure C++, they are both viable programming languages as I have said, and I do not want to start a flame war over this. I also understand that for experienced C\C++ developers this text is merely stating the obvious, the text is aimed at future C\C++ programmers.
rsmemphis
April 2nd, 2003, 01:16 PM
Well, you have actually provided your own answer.
I started with straight C when OO languages were just becoming fashionable. Then I wanted to switch to C++, and I had no idea what it would help me with and what I can do with it.
Fast forward to the blooming of the Internet, when Java was the rage.
I was now FORCED to program OO, and it took me a few hours to realize what it means to overload class members, etc.. I mean, you have to, so that you can draw anything or can execute anything.
So, then, finally, I was able to switch back to C++ and I slowly realized how wonderfully simple programming can get with things like polymorphism and inheritance.
Cuboidz
April 2nd, 2003, 01:41 PM
Indeed, I also learned a lot about OO when programming in Java. So a good idea would be to learn OO in java and then switch to C++ for maximum flexibility.
Graham
April 2nd, 2003, 03:37 PM
The only thing that programming in Java (or C# or SmallTalk, etc.) teaches you is to stick all your code in classes. It does not teach you OO design. You learn that by understanding what the various constructs and idioms actually mean, not what the language spec says happens.
What is the real meaning of public inheritance?
If I use private inheritance, what can you tell me about the base class (assuming I'm sticking to the principle of preferring containment over private inheritance unless ......)?
Consider the following class (a base class in some hierarchy):
class foo // not a complete declaration.
{
public:
void f1();
Complete the following statement in three words: "the function foo::f1() is ...".
Is there a reason why you might want f2 to have protected access, given that it's pure?
What's the point of f4()?
What do f2, f3 and f4 tell you about design patterns that may be used in class foo?
If I have an inheritance hierarchy that contains no virtual destructors, what does that say about the way you should use it?
You'll learn the answers to those questions by learning OO design, not by learning any specific language.
Cuboidz
April 2nd, 2003, 03:55 PM
Well it seems I need to learn some OO design then, because, honestly, your questions leave me baffled. I guess you can blame my lack of experience for that :rolleyes:
Kheun
April 2nd, 2003, 07:42 PM
Although using either C or C++, we can produce any running code. However, there are significant advantages using C++, like code reuse, abstraction, et al. These key OO concepts are very important for code maintenance as well as constructing a stable software architecture which is capable to withstand future requirement changes. I believe that most of us would not like to rewrite the whole code just because of some requirement changes that break the whole software architecture.
Just my 2 cents worth. :)
galathaea
April 3rd, 2003, 12:01 AM
c++ is a language with many facets. Object Oriented programming is one paradigm that fits very well within it, as that was indeed one of its original goals. It inherited the procedural paradigm from its mommy. But with templating and more control over the translation process, c++ has grabbed hold tightly to the generic programming paradigm and indeed this has expanded in many different direction, perhaps the most powerful being generative programming and the automation of design.
But I think all of these things are not at the heart of why c++ is perceived as difficult. I think it is perceived as difficult because there are really really really bad teachers out there that don't understand the importance of proper c++ constructs, idioms, and design and fail completely in endowing their students with any of it. The students in turn don't really understand the reasoning behind the language...
kuphryn
April 3rd, 2003, 01:58 AM
C++ IS dynamic polymorphism(RTTI) plus static polymorphism (template).
C++ owns!
End of discussion.
Kuphryn
Graham
April 3rd, 2003, 12:46 PM
Cuboidz: it's not so much lack of experience as the difference between knowing the what and the how but not knowing the why. Yes, inheritance can simplify code wonderfully, but it can also be used inappropriately if you don't understand why it works. For instance, take the first question I asked:
Public inheritance (in a polymorphic hierarchy) means IS-A. Nothing else. The test is: if you have a function f() which is written in terms of a (pointer or reference to) some class B, then calling f() with an object of class D, publically derived from B, will not materially affect the working of f(). In other words, D can do everything that B can do and in a way that is "sensible". If you write a derived class, and a function that is written in terms of its base class cannot sensibly use that derived class, then you are misusing public inheritance.
Q2: the base class in question has virtual functions that I wish to override. Private inheritance means "implemented in terms of" or "uses". If class D privately inherits from B, then we say D uses B. The "IS-A" relationship does not apply. Now, "uses" is also modelled by containment (a member variable of the appropriate class). For reasons that I won't go into, containment is preferable to private derivation ---- except when the class you are "using" contains virtual functions that you need to override.
Q3: the function foo::f1() is invariant over specialisation. This means that the action performed by f1() does not change for any derived class - all derived classes inherit not only the signature of f1, but also its implementation. Do not override it in any derived class - major bugs lie down that route.
Why might I want a protected pure function? After all, if it's pure, it might as well be private if it's not going to be public. My reason is that foo::f2() has an implementation. Does that surprise anyone? You can provide an implementation for a pure virtual function. Why? To provide a default implementation, but one which you have to explicitly use. Consider if f2() had not been pure: someone deriving from foo could forget to implement an override, and the default implementation would be called whether it was meant or not. By making f2 pure (and protected) I am saying to the author of a derived class "you can use the default implementation of this function, but it must be a concious decision to do so", because the derived class must override f2 and it can only get at the foo::f2 code by putting the call "foo::f2()" in that override. Compare that to f3(), which is private, so there would be no point in providing an implementation since it could never be called.
Which brings us to f4(). What's it saying to the author of a derived class? It's saying "Here is a virtual function with a default implementation. You may accept the default, or you may override the function. If you provide an override, you may not use the default implementation."
What does the presence of non-public virtual functions tell me about the class? That's it's quite likely to be using the Template pattern somewhere (possibly in f1). The Template pattern is used when the processing for a given function is mostly invariant, but some bits of it are polymorphic. So you declare non-public virtual functions for the changeable bits and call them from an invariant function at appropriate points in the invariant code. Because the functions are non-public, only code within the class (or friends) can call them, and that's Template whether you realise it or not.
Finally, a hierarchy with no virtual destructors. Two things to say about it really: it's not polymorphic and I would not expect to see any virtual functions at all. Why do it? Admittedly, the occasions are rare, but this would be a hierarchy designed solely and exclusively for the purpose of factoring out common code among similar classes. You should never have a pointer that points to a more derived object. I would go further and say that it has been designed for extension as well, because, if the hierarchy was fixed, it would be better to factor the common stuff into free functions (which you don't have in Java) in the implementation file, rather than introduce an artificial hierarchy.
There's more to object oriented design than going "hey, cool! Polymorphism!" You need to to know why polymorphism is cool. Not only that but you also need to know how it can be misused and why such misuse is A Bad Thing. Try reading Scott Meyers's books or picking up a book devoted to OOD. You'll be a better programmer for that, no matter which language you start with.
galathaea
April 3rd, 2003, 01:34 PM
Just an expansion on Graham's points (too long to quote usefully). As he points out, polymorphism is the reason for inheritence in the object-oriented paradigm, but there are other reasons that don't require the IS-A relationship; in particular: the mentioned code factoring. This is actually becoming quite a strong use of inheritence in generative programming with the popularity of the policy idiom (aka. the "curiously repeating template pattern"), where the concept of IS-A need not strictly apply since the whole raison d'etre of the idiom is strong, generic code reuse as a plug-in framework.
In fact, generic programing as a whole often uses concepts from c++ in an orthogonal manner to the OOP paradigm. The sizeof keyword, automatic arrays, SFINAE, etc. are used often not as the methods on objects that OOP would entail but as compiler directives to enforce contracts for translationtime assertions, traits enforcement, etc. Ahh the beauty of c++!
mop
April 4th, 2003, 02:43 PM
For reasons that I won't go into, containment is preferable to private derivation ---- except when the class you are "using" contains virtual functions that you need to override.
I thought the impetus behind making a function in the OO world virtual was for 'late binding' purposes?
Excellent post that covered some of the 'fundamentals' . I hope to someday become half as 'good' as most folks on here :)
Graham
April 5th, 2003, 03:31 AM
Originally posted by mop
I thought the impetus behind making a function in the OO world virtual was for 'late binding' purposes?
"late binding" is the mechanism by which we achieve polymorphism, not the impetus, rationale or raison d'etre.
mop
April 7th, 2003, 05:39 AM
I never quite got/understood the OOD fundamentals and this post really cleared some things up. In any event, ordered the book mentioned but a few more questions if I may. Consider this
Compare that to f3(), which is private, so there would be no point in providing an implementation since it could never be called.
Which brings us to f4(). What's it saying to the author of a derived class? It's saying "Here is a virtual function with a default implementation. You may accept the default, or you may override the function. If you provide an override, you may not use the default implementation."
The note ' since it could never be called' confued me a bit, in that is it not safe to state that f3() is akin to f4()?
So now f3() also says to the author of the derived class. "Here is a .... implementation"
One other thing. The 'virtual' keyword just basically says to the author(s) of the derived calss ' you can override' this function.?' Also the NON virtual function f1() cannot be 'overriden'. Correct?
'implemented in terms of' or 'uses' almost implies that ALL functions that need to be overriden - hence the virtual keyword - needs to be private (or protected) inheritance?
public in a polymorphic sense means "IS A"
private is in a polymorphic sense means 'implemented in terms of" or 'uses'
what about protected?
Would it be too much to ask for a devired 'example' on this.
Thanks
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.