2.2. The C++ Experience
As programmers wrestled with OOP, they also dealt with issues related to their
chosen language . Visual Basic developers began to understand that the language
and environment may be simple, but it is prone to poor performance and poor
designs, leaving customers stranded with slow applications that they could not
extend or maintain.
In C++, server-side developers found performance, but discovered another
challenge. They did application development using a systems programming
language. New terminology like memory-stompers and DLL Hell gave testament
to the frustration of the masses. Simple problems dogged them.
2.2.1. Pointer Arithmetic
With C++, a pointer could point to any block of memory, regardless of whether it
was the intention of the programmer. For example, consider the simple program in
Example 2-1. It moves a block of memory from one location to another, and
inverts it. Unfortunately, the example is off by 1. The code touches memory one
byte beyond the from block. You would probably not see the error right away.
You'd see it later, when you tried to manage the memory of this block, or another
one. C and C++ compilers often manage memory with a linked list, and the
pointers to the next block in the list sit just outside the allocated blocks! These
types of errors hurt systems developers, and absolutely murdered applications
developers, who didn't have the background to effectively troubleshoot these types
of problems. Reliability also suffered.
Example 2-1. Move and invert a block of memory
// move and invert from_block into to_block with size size
int i;
for(i=0; i<size; i++) {
to_block[size-i] = from_block[i]; // off by one!
the right place. Lather, rinse, repeat.
Java does not have this problem at all. You deal with only one type of source file,
with one kind of import, and no conditional compilation.
2.2.3. Strings
Many of the largest corporations used C++ for enterprise application development,
even though it had very limited support for managing strings . C programs simply
used arrays of characters for strings, like this:
char str [ ] = "Hello";
This is going to allocate a fixed-length string to str. It's merely an array of
characters. And it can never hold a string longer than six characters. You could
decide to use the C++ string library instead.
C++ did support the C-style string library for some string-like features. For
example, to assign one string to another when the memory has already been
allocated, you need to copy the bytes instead, like this:
strcpy (string1, string2);
C-style strings were ugly, dangerous, and tedious. As with any other type of
pointer manipulation, you can walk off the end of a block and create an error that
may not be discovered for hours or months. C++ strings are far more tedious than
alternatives in languages, including Java.
Beginning in 1997, the ANSI standard for C++ introduced a more formal string.
You could have a more natural representation that looked like this:
String str = "Hello, I'm feeling a little better.";
And many C++
libraries had proprietary string libraries. But the damage was done.
Many programmers already knew C, and never used the C++-style strings.
2.2.4. DLL Hell
On Microsoft operating systems and OS/2, you compiled libraries that might
depend on other libraries
. The operating system linked these together with a feature
called Dynamic Linking Libraries (DLLs) . But the OS did not do any kind of
inheritance, called a mixin .
Multiple inheritance is a powerful tool in the right hands, but it can lead to
significant problems for the novice. Example 2-2 shows an example of multiple
inheritance in action. A Werewolf is part Man and part Wolf. Problems arise when
both Man and Wolf inherit from a common class, called Mammal. If Werewolf
then inherits a method introduced in Mammal, it's ambiguous whether Werewolf
would inherit through Man or Wolf, as in Figure 2-2. This problem, known as the
diamond inheritance problem , illustrates just one of the problems related to
multiple inheritance.
Example 2-2. Multiple inheritance in C++
class Werewolf: public Man, public Wolf
Multiple inheritance is like any power tool. It gives you leverage and speed and
can save you time, but you've got to have enough knowledge and experience to use
it safely and effectively to keep all your fingers and toes. Most developers using
C++ as an applications language had neither.
Figure 2-2. The diamond inheritance problem is just one of the complexities that
can arise with multiple inheritance
2.2.7. Consistency
Like Perl, C++ is most
definitely an expressive language, but that flexibility comes
at an incredible cost. C++ is full of features that might make sense to a seasoned
developer, but that have catastrophic effects at runtime. For example, = often
doubles as an assignment and a test. Most new developers will get burned by this
problem. It takes years and years of study and experience to become proficient
with C++. For systems development, that makes sense, because you ultimately
need the performance and control inherent in the ability to put every byte where
you want to. Applications developers simply don't want to deal with those low-
level details.
2.2.8. Portability