Thursday, April 9, 2015

How long does it take to learn C++?

That depends on what you mean by “learning.” If you are a C programmer you can learn enough C++ to make you more effective at C-style programming in a day.

The book Programming: Principles and Practice using C++ has been used to get thousands of freshmen (1st year students) through the fundamentals of C++ and the programming techniques it supports (notably object-oriented programming and generic programming) in a semester.
On the other hand, if you want to be fully comfortable with all the major C++ language constructs, with data abstraction, Object-Oriented programming, generic programming, Object-Oriented design, etc., you can easily spend a year or two – if you aren’t already acquainted with those techniques (say, from Java or C#).

Is that then the time it takes to learn C++? Maybe, but then again, that is the timescale we have to consider to become better designers and programmers. If a dramatic change of the way we work and think about building systems isn’t our aim, then why bother to learn a new language? Compared to the time required to learn to play the piano well or to become fluent in a foreign (natural) language, learning a new and different programming language and programming style is easy.

For more observations about learning C++ see D&E or a note Bjarne Stroustrup wrote some time ago.

Companies successfully teach standard industry “short courses,” where a university semester course is compressed into one 40 hour work week. But regardless of where you get your training, make sure the courses have a hands-on element, since most people learn best when they have projects to help the concepts “gel.” But even if they have the best training, they’re not ready yet.

It takes 6-12 months to become broadly proficient in C++, especially if you haven’t done OO or generic programming before. It takes less time for developers who have easy access to a “local” body of experts, more if there isn’t a “good” general purpose C++ class library available. To become one of these experts who can mentor others takes around 3 years.

Some people never make it. You don’t have a chance unless you are teachable and have personal drive. As a bare minimum on “teachability,” you have to be able to admit when you’ve been wrong. As a bare minimum on “drive,” you must be willing to put in some extra hours. Remember: it’s a lot easier to learn some new facts than it is to change your paradigm, i.e., to change the way you think; to change your notion of goodness; to change your mental models.
Two things you should do:
  • Get your people two books: one to tell them what is legal, another to tell them what is moral
  • Consider bringing in a “mentor”
Two things you should not do:

  • You should not bother having your people trained in C as a stepping-stone to learning OO/C++
  • You should not bother having your people trained in Objective-C as a stepping-stone to learning OO/C++

What’s the best way to improve my C++ programs?

That depends on how you use it. Most people underestimate abstract classes and templates. Conversely, most people seriously overuse casts and macros. Have a look at one of Stroustrup’s papers or books for ideas. One way of thinking of abstract classes and templates is as interfaces that allow a more clean and logical presentation of services than is easy to provide through functions or single-rooted class hierarchies. See other sections of this FAQ for some specific examples and ideas.

Does it matter which programming language I use?

Yes, but don’t expect miracles. Some people seem to believe that a programming language can or at least should solve most of their problems with system building. They are condemned to search forever for the perfect programming language and become repeatedly disappointed. Others dismiss programming languages as unimportant “implementation details” and put their money into development processes and design methods. They are condemned to program in COBOL, C, and proprietary design languages forever. A good language – such as C++ – can do a lot for a designer and a programmer, as long as its strengths and limitations are clearly understood and respected.

What are some features of C++ from a business perspective?

Here are a few features of OO/C++ from a business perspective:

  • C++ has a huge installed base, which means you’ll have multi-vendor support for tools, environments, consulting services, etc., plus you’ll have a very valuable line-item on your resumé
  • C++ lets developers provide simplified interfaces to software chunks, which improves the defect-rate when those chunks are (re)used
  • C++ lets you exploit developer’s intuition through operator overloading, which reduces the learning curve for (re)users
  • C++ localizes access to a software chunk, which reduces the cost of changes.
  • C++ reduces the safety-vs.-usability tradeoff, which improves the cost of (re)using a chunk of software.
  • C++ reduces the safety-vs.-speed tradeoff, which improves defect rates without degrading performance.
  • C++ gives you inheritance and dynamic binding which let old code call new code, making it possible to quickly extend/adapt your software to hit narrow market windows.

Are virtual functions (dynamic binding) central to OO/C++?

Yes and no! OO-style dynamic polymorphism, which you get by calling virtual functions, is one of the two major ways C++ offers to achieve polymorphism, and the one you should use for things that can’t be known at compile time. The other is generic-programming-style static polymorphism, which you get by using templates, and you should often use for things that are known at compile time. They’re two great tastes that taste great together.

Without virtual functions, C++ wouldn’t be object-oriented. Operator overloading and non-virtual member functions are great, but they are, after all, just syntactic sugar for the more typical C notion of passing a pointer to a struct to a function. The standard library contains numerous templates that illustrate “generic programming” techniques, which are also great, but virtual functions are still at the heart of object-oriented programming using C++.

From a business perspective, there is very little reason to switch from straight C to C++ without virtual functions (for now we’ll ignore generic programming and the standard library). Technical people often think that there is a large difference between C and non-OO C++, but without OO, the difference usually isn’t enough to justify the cost of training developers, new tools, etc. In other words, if I were to advise a manager regarding whether to switch from C to non-OO C++ (i.e., to switch languages but not paradigms), I’d probably discourage him or her unless there were compelling tool-oriented reasons. From a business perspective, OO can help make systems extensible and adaptable, but just the syntax of C++ classes without OO may not even reduce the maintenance cost, and it surely adds to the training cost significantly.

Bottom line: C++ without virtual is not OO. Programming with classes but without dynamic binding is called “object based,” but not “object oriented.” Throwing out virtual functions is the same as throwing out OO. All you have left is object-based programming, similar to the original Ada language (the updated Ada language, by the way, supports true OO rather than just object-based programming).


Note: you don’t need virtual functions for generic programming. Among other things, this means you can’t tell which paradigm you’ve used simply by counting the number of virtual functions you have.

I’m from Missouri. Can you give me a simple reason why virtual functions (dynamic binding, dynamic polymorphism) and templates (static polymorphism) make a big difference?

They can improve reuse by letting old code call new code provided at run time (virtual functions) or compile time (templates).

Before OO and generic programming came along, reuse was accomplished by having new code call old code. For example, a programmer might write some code that called some reusable code such as printf().

With OO and generic programming, reuse can also be accomplished by having old code call new code. For example, a programmer might write some code that is called by a framework that was written by their great, great grandfather. There’s no need to change great-great-grandpa’s code. In fact, for dynamic binding with virtual functions, it doesn’t even need to be recompiled. Even if all you have left is the object file and the source code that great-great-grandpa wrote was lost 25 years ago, that ancient object file will call the new extension without anything falling apart.


That is extensibility, and that is OO and generic programming for powerful reusable abstraction.

Is C++ backward compatible with ANSI/ISO C?

C++ is as close as possible to compatible with C, but no closer. In practice, the major difference is that C++ requires prototypes, and that f() declares a function that takes no parameters (in C, a function declared using f() can be passed an arbitrary number of parameters of arbitrary types).


There are some very subtle differences as well, like sizeof('x') is equal to sizeof(char) in C++ but is equal to sizeof(int) in C. Also, C++ puts structure “tags” in the same namespace as other names, whereas C requires an explicit struct (e.g., the typedef struct Fred Fred; technique still works, but is redundant in C++).

Why is C++ (almost) compatible with C?

When Stroustrup invented C++, he wanted C++ to be compatible with a complete language with sufficient performance and flexibility for even the most demanding systems programming. He “had a perfect dread of producing yet-another pretty language with unintentional limitations.” See Section 2.7 of The Design and Evolution of C++ for historical details.

At the time, Stroustrup considered C the best systems programming language available. That was not as obvious then (1979) as it later became, but Stroustrup had experts such as Dennis Ritchie, Steve Johnson, Sandy Fraser, Greg Chesson, Doug McIlroy, and Brian Kernighan down the corridor from whom he could learn and get feedback. Without their help and advice, and without C, C++ would have been stillborn.


Contrary to repeated rumors, Stroustrup was never told that he had to use C; nor was he ever told not to use C. In fact, the first C++ manual grew from troff source of the C manual contributed by Dennis Ritchie. Many new languages were designed at Bell labs; in “Research” at least, there were no rules enforcing language bigotry.

Why was C++ invented?

Stroustrup wanted to write efficient systems programs in the styles encouraged by Simula67. To do that, he added facilities for better type checking, data abstraction, and object-oriented programming to C. The more general aim was to design a language in which developers could write programs that were both efficient and elegant. Many languages force you to choose between those two alternatives.


The specific tasks that caused Stroustrup to start designing and implementing C++ (initially called “C with Classes”) had to do with distributing operating system facilities across a network.

Where did the name C++ come from?

In Chapter 3 of D&E, Stroustrup wrote:
I picked C++ because it was short, had nice interpretations, and wasn’t of the form “adjective C.”
In C, ++ can, depending on context, be read as “next,” “successor,” or “increment,” though it is always pronounced “plus plus.” The name C++ and its runner up ++C are fertile sources for jokes and puns – almost all of which were known and appreciated before the name was chosen. The name C++ was suggested by Rick Mascitti. It was first used in December of 1983 when it was edited into the final copies of [Stroustrup,1984] and [Stroustrup,1984c].
In chapter 1 of TC++PL, Stroustrup wrote:
The name C++ (pronounced “see plus plus”) was coined by Rick Mascitti in the summer of 1983. The name signifies the evolutionary nature of the changes from C; “++” is the C increment operator. The slightly shorter name “C+” is a syntax error; it has also been used as the name of an unrelated language. Connoisseurs of C semantics find C++ inferior to ++C. The language is not called D, because it is an extension of C, and it does not attempt to remedy problems by removing features. For yet another interpretation of the name C++, see the appendix of [Orwell,1949].

The “C” in C++ has a long history. Naturally, it is the name of the language Dennis Ritchie designed. C’s immediate ancestor was an interpreted descendant of BCPL called B designed by Ken Thompson. BCPL was designed and implemented by Martin Richards from Cambridge University while visiting MIT in the other Cambridge. BCPL in turn was Basic CPL, where CPL is the name of a rather large (for its time) and elegant programming language developed jointly by the universities of Cambridge and London. Before the London people joined the project “C” stood for Cambridge. Later, “C” officially stood for Combined. Unofficially, “C” stood for Christopher because Christopher Strachey was the main power behind CPL.

Why does C++ allow unsafe code?

That is, why does C++ support operations that can be used to violate the rules of static (compile-time) type safety?
  • to access hardware directly (e.g. to treat an integer as a pointer to (address of) a device register)
  • to achieve optimal run-time and space performance (e.g. unchecked access to elements of an array and unchecked access to an object through a pointer)
  • to be compatible with C
That said, it is a good idea to avoid unsafe code like the plague whenever you don’t actually need one of those three features:
  • don’t use casts
  • keep C-style [] arrays out of interfaces (hide them in the innards of high-performance functions and classes where they are needed and write the rest of the program using proper strings, vectors, etc.)
  • avoid void* (keep them inside low-level functions and data structures if you really need them and present type safe interfaces, usually templates, to your users)
  • avoid unions
  • if you have any doubts about the validity of a pointer, use a smart pointer instead
  • don’t use “naked” new and delete (use containers, resource handles, etc., instead)
  • don’t use ...-style variadic functions (“printf style”)
  • avoid macros except for #include guards

Almost all C++ code can follow these simple rules. Please don’t be confused by the fact that you cannot follow these rules if you write C code or C-style code in C++.

Why are some things left undefined in C++?

Because machines differ and because C left many things undefined. For details, including definitions of the terms “undefined”, “unspecified”, “implementation defined”, and “well-formed”; see the ISO C++ standard. Note that the meaning of those terms differ from their definition of the ISO C standard and from some common usage. You can get wonderfully confused discussions when people don’t realize that not everybody shares definitions.

This is a correct, if unsatisfactory, answer. Like C, C++ is meant to exploit hardware directly and efficiently. This implies that C++ must deal with hardware entities such as bits, bytes, words, addresses, integer computations, and floating-point computations the way they are on a given machine, rather than how we might like them to be. Note that many “things” that people refer to as “undefined” are in fact “implementation defined”, so that we can write perfectly specified code as long as we know which machine we are running on. Sizes of integers and the rounding behavior of floating-point computations fall into that category.

Consider what is probably the the best known and most infamous example of undefined behavior:

The C++ (and C) notion of array and pointer are direct representations of a machine’s notion of memory and addresses, provided with no overhead. The primitive operations on pointers map directly onto machine instructions. In particular, no range checking is done. Doing range checking would impose a cost in terms of run time and code size. C was designed to outcompete assembly code for operating systems tasks, so that was a necessary decision. Also, C – unlike C++ – has no reasonable way of reporting a violation had a compiler decided to generate code to detect it: There are no exceptions in C. C++ followed C for reasons of compatibility and because C++ also compete directly with assembler (in OS, embedded systems, and some numeric computation areas). If you want range checking, use a suitable checked class (vector, smart pointer, string, etc.). A good compiler could catch the range error for a[100] at compile time, catching the one for p[100] is far more difficult, and in general it is impossible to catch every range error at compile time.
Other examples of undefined behavior stems from the compilation model. A compiler cannot detect an inconsistent definition of an object or a function in separately-compiled translation units. For example:



Compiling file1.c and file2.c and linking the results into the same program is illegal in both C and C++. A linker could catch the inconsistent definition of S, but is not obliged to do so (and most don’t). In many cases, it can be quite difficult to catch inconsistencies between separately compiled translation units. Consistent use of header files helps minimize such problems and there are some signs that linkers are improving. Note that C++ linkers do catch almost all errors related to inconsistently declared functions.
Finally, we have the apparently unnecessary and rather annoying undefined behavior of individual expressions. For example:

The value of j is unspecified to allow compilers to produce optimal code. It is claimed that the difference between what can be produced giving the compiler this freedom and requiring “ordinary left-to-right evaluation” can be significant. Leading experts are unconvinced, but with innumerable compilers “out there” taking advantage of the freedom and some people passionately defending that freedom, a change would be difficult and could take decades to penetrate to the distant corners of the C and C++ worlds. It is disappointing that not all compilers warn against code such as ++i+i++. Similarly, the order of evaluation of arguments is unspecified.

There is a sentiment that too many “things” are left undefined, unspecified, implementation-defined, etc. To address this, the ISO C++ committee has created Study Group 12 to review and recommend wide-ranging tightening-up to reduce undefined, unspecified, and implementation-defined behavior.

Why is portability considered so important?

Successful software is long-lived; life-spans of decades are not uncommon. A good application/program often outlives the hardware it was designed for, the operating system it was written for, the data base system it initially used, etc. Often, a good piece of software outlives the companies that supplied the basic technologies used to build it.

Often a successful application/program have customers/users who prefer a variety of platforms. The set of desirable platforms change as the user population changes. Being tied to a single platform or single vendor, limits the application/program’s potential use.


Obviously, complete platform independence is incompatible with the ability to use all platform specific facilities. However, you can often approximate platform independence for an application by accessing platform facilities through a “thin interface” representing the application’s view of its environment as a library.