- Day 1
Getting Started
Introduction
A Brief History of C++
Programs
Solving Problems
Procedural, Structured, and Object-Oriented
Programming
C++ and Object-Oriented Programming
How C++ Evolved
The ANSI Standard
Should I Learn C First?
Preparing to Program
Your Development Environment
Compiling the Source Code
Creating an Executable File with the Linker
The Development Cycle
Figure 1.1.
HELLO.CPPYour First C++ Program
Listing 1.1. HELLO.CPP, the Hello World
program.
Compile Errors
Listing 1.2. Demonstration of
compiler error.
Summary
Q&A
Workshop
Quiz
Exercises
Introduction
Welcome to Teach Yourself C++ in 21
Days! Today you will get started on your way to becoming
a proficient C++ programmer. You'll learn
- Why C++ is the emerging standard in software
development.
-
-
The steps to develop a C++ program.
-
How to enter, compile, and link your first working
C++ program.
A Brief History
of C++
Computer languages have undergone
dramatic evolution since the first electronic computers
were built to assist in telemetry calculations during
World War II. Early on, programmers worked with the most
primitive computer instructions: machine language. These
instructions were represented by long strings of ones
and zeroes. Soon, assemblers were invented to map
machine instructions to human-readable and -manageable
mnemonics, such as ADD and MOV.
In time, higher-level languages evolved,
such as BASIC and COBOL. These languages let people work
with something approximating words and sentences, such
as Let I = 100. These instructions were
translated back into machine language by interpreters
and compilers. An interpreter translates a program as it
reads it, turning the program instructions, or code,
directly into actions. A compiler translates the code
into an intermediary form. This step is called
compiling, and produces an object file. The compiler
then invokes a linker, which turns the object file into
an executable program.
Because interpreters read the code as it
is written and execute the code on the spot,
interpreters are easy for the programmer to work with.
Compilers, however, introduce the extra steps of
compiling and linking the code, which is inconvenient.
Compilers produce a program that is very fast each time
it is run. However, the time-consuming task of
translating the source code into machine language has
already been accomplished.
Another advantage of many compiled
languages like C++ is that you can distribute the
executable program to people who don't have the
compiler. With an interpretive language, you must have
the language to run the program.
For many years, the principle goal of
computer programmers was to write short pieces of code
that would execute quickly. The program needed to be
small, because memory was expensive, and it needed to be
fast, because processing power was also expensive. As
computers have become smaller, cheaper, and faster, and
as the cost of memory has fallen, these priorities have
changed. Today the cost of a programmer's time far
outweighs the cost of most of the computers in use by
businesses. Well-written, easy-to-maintain code is at a
premium. Easy- to-maintain means that as business
requirements change, the program can be extended and
enhanced without great expense.
Programs
The word program is used in two ways: to
describe individual instructions, or source code,
created by the programmer, and to describe an entire
piece of executable software. This distinction can cause
enormous confusion, so we will try to distinguish
between the source code on one hand, and the executable
on the other.
-
New Term: A program can be defined
as either a set of written instructions created by
a programmer or an executable piece of software.
Source code can be turned into an
executable program in two ways: Interpreters translate
the source code into computer instructions, and the
computer acts on those instructions immediately.
Alternatively, compilers translate source code into a
program, which you can run at a later time. While
interpreters are easier to work with, most serious
programming is done with compilers because compiled code
runs much faster. C++ is a compiled language.
Solving Problems
The problems programmers are asked to
solve have been changing. Twenty years ago, programs
were created to manage large amounts of raw data. The
people writing the code and the people using the program
were all computer professionals. Today, computers are in
use by far more people, and most know very little about
how computers and programs work. Computers are tools
used by people who are more interested in solving their
business problems than struggling with the computer.
Ironically, in order to become easier to
use for this new audience, programs have become far more
sophisticated. Gone are the days when users typed in
cryptic commands at esoteric prompts, only to see a
stream of raw data. Today's programs use sophisticated
"user-friendly interfaces," involving multiple
windows, menus, dialog boxes, and the myriad of
metaphors with which we've all become familiar. The
programs written to support this new approach are far
more complex than those written just ten years ago.
As programming requirements have
changed, both languages and the techniques used for
writing programs have evolved. While the complete
history is fascinating, this book will focus on the
transformation from procedural programming to
object-oriented programming.
Procedural,
Structured, and Object-Oriented Programming
Until recently, programs were thought of
as a series of procedures that acted upon data. A
procedure, or function, is a set of specific
instructions executed one after the other. The data was
quite separate from the procedures, and the trick in
programming was to keep track of which functions called
which other functions, and what data was changed. To
make sense of this potentially confusing situation,
structured programming was created.
The principle idea behind structured
programming is as simple as the idea of divide and
conquer. A computer program can be thought of as
consisting of a set of tasks. Any task that is too
complex to be described simply would be broken down into
a set of smaller component tasks, until the tasks were
sufficiently small and self-contained enough that they
were easily understood.
As an example, computing the average
salary of every employee of a company is a rather
complex task. You can, however, break it down into these
subtasks:
- 1. Find out what each person earns.
2. Count how many people you have.
3. Total all the salaries.
4. Divide the total by the number of people
you have.
Totaling the salaries can be broken down
into
- 1. Get each employee's record.
2. Access the salary.
3. Add the salary to the running total.
4. Get the next employee's record.
In turn, obtaining each employee's
record can be broken down into
- 1. Open the file of employees.
2. Go to the correct record.
3. Read the data from disk.
Structured programming remains an
enormously successful approach for dealing with complex
problems. By the late 1980s, however, some of the
deficiencies of structured programing had became all too
clear.
First, it is natural to think of your
data (employee records, for example) and what you can do
with your data (sort, edit, and so on) as related ideas.
Second, programmers found themselves
constantly reinventing new solutions to old problems.
This is often called "reinventing the wheel,"
and is the opposite of reusability. The idea behind
reusability is to build components that have known
properties, and then to be able to plug them into your
program as you need them. This is modeled after the
hardware world--when an engineer needs a new transistor,
she doesn't usually invent one, she goes to the big bin
of transistors and finds one that works the way she
needs it to, or perhaps modifies it. There was no
similar option for a software engineer.
-
New Term: The way we are now using
computers--with menus and buttons and
windows--fosters a more interactive, event-driven
approach to computer programming. Event-driven
means that an event happens--the user presses a
button or chooses from a menu--and the program
must respond. Programs are becoming increasingly
interactive, and it has became important to design
for that kind of functionality.
Old-fashioned programs forced the user
to proceed step-by-step through a series of screens.
Modern event-driven programs present all the choices at
once and respond to the user's actions.
Object-oriented programming attempts to
respond to these needs, providing techniques for
managing enormous complexity, achieving reuse of
software components, and coupling data with the tasks
that manipulate that data.
The essence of object-oriented
programming is to treat data and the procedures that act
upon the data as a single "object"--a
self-contained entity with an identity and certain
characteristics of its own.
C++ and
Object-Oriented Programming
C++ fully supports object-oriented
programming, including the four pillars of
object-oriented development: encapsulation, data hiding,
inheritance, and polymorphism. Encapsulation and Data
Hiding When an engineer needs to add a resistor to the
device she is creating, she doesn't typically build a
new one from scratch. She walks over to a bin of
resistors, examines the colored bands that indicate the
properties, and picks the one she needs. The resistor is
a "black box" as far as the engineer is
concerned--she doesn't much care how it does its work as
long as it conforms to her specifications; she doesn't
need to look inside the box to use it in her design.
The property of being a self-contained
unit is called encapsulation. With encapsulation, we can
accomplish data hiding. Data hiding is the highly valued
characteristic that an object can be used without the
user knowing or caring how it works internally. Just as
you can use a refrigerator without knowing how the
compressor works, you can use a well-designed object
without knowing about its internal data members.
Similarly, when the engineer uses the
resistor, she need not know anything about the internal
state of the resistor. All the properties of the
resistor are encapsulated in the resistor object; they
are not spread out through the circuitry. It is not
necessary to understand how the resistor works in order
to use it effectively. Its data is hidden inside the
resistor's casing.
C++ supports the properties of
encapsulation and data hiding through the creation of
user-defined types, called classes. You'll see how to
create classes on Day 6, "Basic Classes." Once
created, a well-defined class acts as a fully
encapsulated entity--it is used as a whole unit. The
actual inner workings of the class should be hidden.
Users of a well-defined class do not need to know how
the class works; they just need to know how to use it.
Inheritance and Reuse When the engineers at Acme Motors
want to build a new car, they have two choices: They can
start from scratch, or they can modify an existing
model. Perhaps their Star model is nearly perfect, but
they'd like to add a turbocharger and a six-speed
transmission. The chief engineer would prefer not to
start from the ground up, but rather to say, "Let's
build another Star, but let's add these additional
capabilities. We'll call the new model a Quasar." A
Quasar is a kind of Star, but one with new features.
C++ supports the idea of reuse through
inheritance. A new type, which is an extension of an
existing type, can be declared. This new subclass is
said to derive from the existing type and is sometimes
called a derived type. The Quasar is derived from the
Star and thus inherits all its qualities, but can add to
them as needed. Inheritance and its application in C++
are discussed on Day 12, "Inheritance," and
Day 15, "Advanced Inheritance." Polymorphism
The new Quasar might respond differently than a Star
does when you press down on the accelerator. The Quasar
might engage fuel injection and a turbocharger, while
the Star would simply let gasoline into its carburetor.
A user, however, does not have to know about these
differences. He can just "floor it," and the
right thing will happen, depending on which car he's
driving.
C++ supports the idea that different
objects do "the right thing" through what is
called function polymorphism and class polymorphism.
Poly means many, and morph means form. Polymorphism
refers to the same name taking many forms, and is
discussed on Day 10, "Advanced Functions," and
Day 13, "Polymorphism."
How C++ Evolved
As object-oriented analysis, design, and
programming began to catch on, Bjarne Stroustrup took
the most popular language for commercial software
development, C, and extended it to provide the features
needed to facilitate object-oriented programming. He
created C++, and in less than a decade it has gone from
being used by only a handful of developers at AT&T
to being the programming language of choice for an
estimated one million developers worldwide. It is
expected that by the end of the decade, C++ will be the
predominant language for commercial software
development.
While it is true that C++ is a superset
of C, and that virtually any legal C program is a legal
C++ program, the leap from C to C++ is very significant.
C++ benefited from its relationship to C for many years,
as C programmers could ease into their use of C++. To
really get the full benefit of C++, however, many
programmers found they had to unlearn much of what they
knew and learn a whole new way of conceptualizing and
solving programming problems.
The ANSI
Standard
The Accredited Standards Committee,
operating under the procedures of the American National
Standards Institute (ANSI), is working to create an
international standard for C++.
The draft of this standard has been
published, and a link is available at www.libertyassociates.com.
The ANSI standard is an attempt to
ensure that C++ is portable--that code you write for
Microsoft's compiler will compile without errors, using
a compiler from any other vendor. Further, because the
code in this book is ANSI compliant, it should compile
without errors on a Mac, a Windows box, or an Alpha.
For most students of C++, the ANSI
standard will be invisible. The standard has been stable
for a while, and all the major manufacturers support the
ANSI standard. We have endeavored to ensure that all the
code in this edition of this book is ANSI compliant.
Should I Learn
C First?
The question inevitably arises:
"Since C++ is a superset of C, should I learn C
first?" Stroustrup and most other C++ programmers
agree. Not only is it unnecessary to learn C first, it
may be advantageous not to do so. This book attempts to
meet the needs of people like you, who come to C++
without prior experience of C. In fact, this book
assumes no programming experience of any kind.
Preparing to
Program
C++, perhaps more than other languages,
demands that the programmer design the program before
writing it. Trivial problems, such as the ones discussed
in the first few chapters of this book, don't require
much design. Complex problems, however, such as the ones
professional programmers are challenged with every day,
do require design, and the more thorough the design, the
more likely it is that the program will solve the
problems it is designed to solve, on time and on budget.
A good design also makes for a program that is
relatively bug-free and easy to maintain. It has been
estimated that fully 90 percent of the cost of software
is the combined cost of debugging and maintenance. To
the extent that good design can reduce those costs, it
can have a significant impact on the bottom-line cost of
the project.
The first question you need to ask when
preparing to design any program is, "What is the
problem I'm trying to solve?" Every program should
have a clear, well-articulated goal, and you'll find
that even the simplest programs in this book do so.
The second question every good
programmer asks is, "Can this be accomplished
without resorting to writing custom software?"
Reusing an old program, using pen and paper, or buying
software off the shelf is often a better solution to a
problem than writing something new. The programmer who
can offer these alternatives will never suffer from lack
of work; finding less-expensive solutions to today's
problems will always generate new opportunities later.
Assuming you understand the problem, and
it requires writing a new program, you are ready to
begin your design.
Your
Development Environment
This book makes the assumption that your
computer has a mode in which you can write directly to
the screen, without worrying about a graphical
environment, such as the ones in Windows or on the
Macintosh.
Your compiler may have its own built-in
text editor, or you may be using a commercial text
editor or word processor that can produce text files.
The important thing is that whatever you write your
program in, it must save simple, plain-text files, with
no word processing commands embedded in the text.
Examples of safe editors include Windows Notepad, the
DOS Edit command, Brief, Epsilon, EMACS, and vi. Many
commercial word processors, such as WordPerfect, Word,
and dozens of others, also offer a method for saving
simple text files.
The files you create with your editor
are called source files, and for C++ they typically are
named with the extension .CPP, .CP, or
.C. In this book, we'll name all the source
code files with the .CPP extension, but check
your compiler for what it needs.
NOTE: Most C++ compilers don't care what
extension you give your source code, but if you
don't specify otherwise, many will use .CPP
by default.
DO use a simple text editor to create
your source code, or use the built-in editor that
comes with your compiler. DON'T use a word processor
that saves special formatting characters. If you do
use a word processor, save the file as ASCII text. DO
save your files with the .C, .CP, or
.CPP extension. DO check your documentation
for specifics about your compiler and linker to ensure
that you know how to compile and link your programs.
Compiling the
Source Code
Although the source code in your file is
somewhat cryptic, and anyone who doesn't know C++ will
struggle to understand what it is for, it is still in
what we call human-readable form. Your source code file
is not a program, and it can't be executed, or run, as a
program can.
To turn your source code into a program,
you use a compiler. How you invoke your compiler, and
how you tell it where to find your source code, will
vary from compiler to compiler; check your
documentation. In Borland's Turbo C++ you pick the RUN
menu command or type
from the command line, where <filename>
is the name of your source code file (for example, test.cpp).
Other compilers may do things slightly differently.
NOTE: If you compile the source code from the
operating system's command line, you should type the
following:
For the Borland C++ compiler: bcc
<filename>
For the Borland C++ for Windows compiler: bcc
<filename>
For the Borland Turbo C++ compiler: tc
<filename>
For the Microsoft compilers: cl
<filename>
After your source code is compiled, an
object file is produced. This file is often named with
the extension .OBJ. This is still not an
executable program, however. To turn this into an
executable program, you must run your linker.
Creating an
Executable File with the Linker
C++ programs are typically created by
linking together one or more OBJ files with one or more
libraries. A library is a collection of linkable files
that were supplied with your compiler, that you
purchased separately, or that you created and compiled.
All C++ compilers come with a library of useful
functions (or procedures) and classes that you can
include in your program. A function is a block of code
that performs a service, such as adding two numbers or
printing to the screen. A class is a collection of data
and related functions; we'll be talking about classes a
lot, starting on Day 5, "Functions."
The steps to create an executable file
are
- 1. Create a source code file, with a .CPP
extension.
2. Compile the source code into a file with
the .OBJ extension.
3. Link your OBJ file with any needed
libraries to produce an executable program.
The Development
Cycle
If every program worked the first time
you tried it, that would be the complete development
cycle: Write the program, compile the source code, link
the program, and run it. Unfortunately, almost every
program, no matter how trivial, can and will have
errors, or bugs, in the program. Some bugs will cause
the compile to fail, some will cause the link to fail,
and some will only show up when you run the program.
Whatever type of bug you find, you must
fix it, and that involves editing your source code,
recompiling and relinking, and then rerunning the
program. This cycle is represented in Figure 1.1, which
diagrams the steps in the development cycle.
Figure 1.1. The steps in the
development of a C++ program.
Traditional programming books begin by
writing the words Hello World to the screen, or
a variation on that statement. This time-honored
tradition is carried on here.
Type the first program directly into
your editor, exactly as shown. Once you are certain it
is correct, save the file, compile it, link it, and run
it. It will print the words Hello World to your
screen. Don't worry too much about how it works, this is
really just to get you comfortable with the development
cycle. Every aspect of this program will be covered over
the next couple of days.
WARNING: The following listing contains line
numbers on the left. These numbers are for reference
within the book. They should not be typed in to your
editor. For example, in line 1 of Listing 1.1, you
should enter:
Listing
1.1. HELLO.CPP, the Hello World program.
1: #include <iostream.h>
2:
3: int main()
4: {
5: cout << "Hello World!\n";
6: return 0;
7: }
Make certain you enter this exactly as
shown. Pay careful attention to the punctuation. The <<
in line 5 is the redirection symbol, produced on most
keyboards by holding the Shift key and pressing the
comma key twice. Line 5 ends with a semicolon; don't
leave this off!
Also check to make sure you are
following your compiler directions properly. Most
compilers will link automatically, but check your
documentation. If you get errors, look over your code
carefully and determine how it is different from the
above. If you see an error on line 1, such as cannot
find file iostream.h, check your compiler
documentation for directions on setting up your include
path or environment variables. If you receive an error
that there is no prototype for main, add the
line int main(); just before line 3. You will
need to add this line before the beginning of the main
function in every program in this book. Most compilers
don't require this, but a few do.
Your finished program will look like
this:
1: #include <iostream.h>
2:
3:
4: int main();
5: {
6: cout <<"Hello World!\n";
7: return 0;
8: }
Try running HELLO.EXE; it
should write
directly to your screen. If so,
congratulations! You've just entered, compiled, and run
your first C++ program. It may not look like much, but
almost every professional C++ programmer started out
with this exact program.
Compile Errors
Compile-time errors can occur for any
number of reasons. Usually they are a result of a typo
or other inadvertent minor error. Good compilers will
not only tell you what you did wrong, they'll point you
to the exact place in your code where you made the
mistake. The great ones will even suggest a remedy!
You can see this by intentionally
putting an error into your program. If HELLO.CPP
ran smoothly, edit it now and remove the closing brace
on line 6. Your program will now look like Listing 1.2.
Listing
1.2. Demonstration of compiler error.
1: #include <iostream.h>
2:
3: int main()
4: {
5: cout << "Hello World!\n";
6: return 0;
Recompile your program and you should see an error that
looks similar to the following:
This error tells you the file and line
number of the problem, and what the problem is (although
I admit it is somewhat cryptic). Note that the error
message points you to line 5. The compiler wasn't sure
if you intended to put the closing brace before or after
the cout statement on line 5. Sometimes the
errors just get you to the general vicinity of the
problem. If a compiler could perfectly identify every
problem, it would fix the code itself.
Summary
After reading this chapter, you should
have a good understanding of how C++ evolved and what
problems it was designed to solve. You should feel
confident that learning C++ is the right choice for
anyone interested in programming in the next decade. C++
provides the tools of object-oriented programming and
the performance of a systems-level language, which makes
C++ the development language of choice.
Today you learned how to enter, compile,
link, and run your first C++ program, and what the
normal development cycle is. You also learned a little
of what object-oriented programming is all about. You
will return to these topics during the next three weeks.
Q&A
- Q. What is the difference between a text
editor and a word processor?
A. A text editor produces files with plain
text in them. There are no formatting commands or
other special symbols required by a particular
word processor. Text files do not have automatic
word wrap, bold print, italics, and so forth.
Q. If my compiler has a built-in editor, must I
use it?
A. Almost all compilers will compile code
produced by any text editor. The advantages of
using the built-in text editor, however, might
include the ability to quickly move back and forth
between the edit and compile steps of the
development cycle. Sophisticated compilers include
a fully integrated development environment,
allowing the programmer to access help files,
edit, and compile the code in place, and to
resolve compile and link errors without ever
leaving the environment.
Q. Can I ignore warning messages from my
compiler?
A. Many books hedge on this one, but I'll
stake myself to this position: No! Get into the
habit, from day one, of treating warning messages
as errors. C++ uses the compiler to warn you when
you are doing something you may not intend. Heed
those warnings, and do what is required to make
them go away.
Q. What is compile time?
A. Compile time is the time when you run
your compiler, as opposed to link time (when you
run the linker) or run-time (when running the
program). This is just programmer shorthand to
identify the three times when errors usually
surface.
Workshop
The Workshop provides quiz questions to
help you solidify your understanding of the material
covered and exercises to provide you with experience in
using what you've learned. Try to answer the quiz and
exercise questions before checking the answers in
Appendix D, and make sure you understand the answers
before continuing to the next chapter.
Quiz
- 1. What is the difference between an
interpreter and a compiler?
2. How do you compile the source code with
your compiler?
3. What does the linker do?
4. What are the steps in the normal
development cycle?
Exercises
- 1. Look at the following program and try
to guess what it does without running it.
1: #include <iostream.h>
2: int main()
3: {
4: int x = 5;
5: int y = 7;
6: cout "\n";
7: cout << x + y << " " << x * y;
8: cout "\n";
9:return 0;
10: }
- 2. Type in the program from Exercise 1,
and then compile and link it. What does it do?
Does it do what you guessed?
3. Type in the following program and
compile it. What error do you receive?
1: include <iostream.h>
2: int main()
3: {
4: cout << "Hello World\n";
5: return 0;
6: }
- 4. Fix the error in the program in
Exercise 3, and recompile, link, and run it. What
does it do