Tải bản đầy đủ - 0 (trang)
Chapter 2. Getting Started Quickly: A Brief Overview of C++

Chapter 2. Getting Started Quickly: A Brief Overview of C++

Tải bản đầy đủ - 0trang

file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



Topics in this Chapter

ϒΠ



The Basic Program Structure



ϒΠ



Preprocessor Directives



ϒΠ



Comments



ϒΠ



Declarations and Definitions



ϒΠ



Statements and Expressions



ϒΠ



Functions and Function Calls



ϒΠ



Classes



ϒΠ



Dealing with Program Development Tools



ϒΠ



Summary



In this chapter, I will briefly preview the basic programming constructs of the C++ language before

going on to discuss them in more depth in the chapters that follow. Because C++ is a large

language, anything that is "brief" is not going to cover much of the language, and anything that

indeed reviews the most important features of the language is not going to be "brief." I will try to

strike a reasonable compromise.

Studying a language like C++ feature by feature cannot give you a general picture that would

connect different features into a cohesive whole. Many features are intertwined and cannot be

discussed separately. This is why you need this preview. It will give you the first look at the most

important concepts and constructs of the C++ language, will enable you to write your first C++

programs, and will prepare you for studying these concepts and techniques in depth and in breadth.

The programs in this book are written using the ISO/ANSI standard C++. This version of the

language adds new features and also changes the syntax of some existing features. There are still

many compilers in use in industry that implement only some features of the new language. There

are too many different vendors and too many different compiler versions to discuss their

differences in implementing standard C++ in detail. Eventually, older compilers will be replaced by

newer versions. However, the industry will have to deal with the code written in prestandard C++

for many years to come. This old code will be supported by newer compilers as well, because

backward compatibility is one of the important goals of C++ design, and standard C++ adds new

file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (43 of 1187) [8/17/2002 2:57:44 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



features without making old features illegal. As a rule, I will cover new standard C++ syntax

without mentioning that explicitly. Where necessary, I will make reference to older ways of writing

code to make sure you can deal with legacy code with confidence.



The Basic Program Structure

Listing 2.1 shows the source code for your first C++ program. It welcomes you to the world of C++

(as most first programs in programming language books do). In addition, just to demonstrate more

features than a canonical "Hello World" program does, it makes some simple computations and

prints the result of raising the value of pi (3.1415926) to the power of two.



Example 2.1. Your first C++ program.

#include

// preprocessor directive

#include

// preprocessor directive

using namespace std;

// compiler directive

const double PI = 3.1415926;

// definition of a constant

int main(void)

// function returns integer

{

double x=PI, y=1, z;

// definitions of variables

cout << "Welcome to the C++ world!" << endl;

// function call

z = y + 1;

// assignment statement

y = pow(x,z);

// function call

cout << "In that world, pi square is " << y << endl;

cout << "Have a nice day!" << endl;

return 0;

// return statement

}

// end of the function block



Do not worry if this program looks obscure. By the end of this chapter, you will understand every

detail here (and more).

Similar to other modern programming languages, C++ allows us to write instructions to the

computer in the form of human-readable source code. The C++ compiler translates the source code

into machine-readable object code. During program execution, machine language instructions are

executed one after another and produce the results.

Most computations are performed over values that are stored in computer memory. For our

purposes, we can think of computer memory as an array of locations with values. Locations cannot

be referred to by the values that are stored in them. They can be referred to either by their numeric

addresses (in the object code) or by their symbolic names (in the source code). For example, our

first C++ program contains the statement:

z = y + 1;



It instructs the computer to fetch the value that is stored at the location named y, increment that

file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (44 of 1187) [8/17/2002 2:57:44 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



value (without changing the contents at location y), and put the result into the location labeled z.

The real addresses of locations named y and z are specified in the executable code but not in the

source code; the programmer makes up these symbolic names but has no interest in what memory

addresses are assigned by the compiler to each name.

In real memory, integers, floating point numbers, and characters (text) are allocated different

numbers of bits and bytes, and their bit patterns are handled differently at run time. To generate

executable code correctly, the compiler has to understand the programmer's intent. This is why

before the statement z=y+1; can be executed, the compiler has to be told that y and z are indeed

symbolic names for locations in memory (and not for other things, e.g., functions) and that the

values stored in memory under these names are of the type double (one of C++ designations for

numbers with fractional parts).

So, most of the source code that the programmer writes either defines the objects that the program

manipulates (here, their names are x, y, z and others specified in #include and #define

directives) or describes what should be done with these objects (add, assign, pass as a parameter to

a function).

The source code for a C++ program can be an ordinary text file created by a text editor, like Emacs

or Vi on Unix, Edt on VMS, or by an Integrated Development Environment (IDE) on PC or Mac.

Here we save it as a file on the hard disk.

Usually, you give your source code files the names you see fit, but you are limited as to what file

name extension to use. Depending on the compiler, source files should be saved with file name

extension .cc, .cpp, or .cxx. Using other extensions is possible but less convenient. When standard

extensions are used, only the name of the source file has to be specified, and the development tools

append the extension automatically. Nonstandard extensions are allowed (and frowned on) but they

have to be specified explicitly.

The source file can define several functions (our first C++ program has only one; its name is main).

The program can consist of several source files (this program has only one). Each source file has to

be compiled, producing the object file. Most environments require that the compiled program

(object files) be linked before it can be executed. (You will learn more about that later in the

chapter.) Figure 2-1 shows the output of execution of our first C++ program.



Figure 2.1. Output of our first C++ program produced by a Microsoft compiler.



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (45 of 1187) [8/17/2002 2:57:44 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



This output was produced by the executable file generated by the Microsoft Visual C++ compiler,

Professional Edition version 6.0. It is a part of Microsoft Development Studio, which integrates

several development tools in the same package. The program was called by the Development

Studio. The last line of the output is generated by the compiler, not by the program. Otherwise, the

window would be removed from the screen immediately after program termination, and the user

would not be able to inspect the program output. Older versions of the Microsoft compiler do not

add this message, but they do not remove the window from the screen either¡Xthe user has to do

that. The program can also be run as a stand-alone application directly from the DOS prompt. In

that case, the last line does not appear. Figure 2-2 shows the result of running this program from the

DOS prompt.



Figure 2.2. Output of our first C++ program run from the DOS command prompt.



The numeric output on different machines might be somewhat different as well. This depends on

the default setting for the number of digits in the output. C++ allows the programmer to explicitly

specify the format of the output, so that it does not depend on the compiler settings, but it is rather

complex and does not belong to this preview. You will see the examples of doing that later.

Our first C++ program demonstrates the following components that should be present in any C++

program:

ϒΠ



preprocessor directives



ϒΠ



comments



ϒΠ



declarations and definitions



ϒΠ



statements and expressions



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (46 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



ϒΠ



functions and function calls



In the following sections I'll discuss the use of each kind of program component in more detail.



Preprocessor Directives

In most other languages, what you write in the source file is what the compiler sees during

compilation. This is not the case in C++. The compiler is not the first tool that deals with the source

code on its way to becoming an executable program. The first tool that processes the source code is

the preprocessor. What is this? Well, it is an interesting invention that C++ inherited from C. Its

goal is to decrease the amount of source code that the programmer writes during development (or

reads during debugging or maintenance).

The preprocessor processes the source file and passes the results of processing to the compiler for

compilation. Most of the program statements are ignored by the preprocessor and are passed to the

compiler unmodified. The preprocessor pays attention only to preprocessor directives (and to

statements that are related to them).

The preprocessor directives start with a '#' and take up the whole line. You cannot put more than

one directive on a single source line. If the directive does not fit into one source line, it can be

continued on the next line, but the previous line should be ended by a special continuation

character, the escape character '\'. The pound sign '#' should be the first character on the line. What

about the free format of C++ source code? In the previous chapter, I told you that you can format

C++ code the way you (and not the compiler) see fit. Well, formally, preprocessor directives are

not part of the C++ (or C) language, and the preprocessor is not part of the compiler.

In practice, of course, you cannot write even a simple C++ program without using preprocessor

directives, but in theory, these directives are not part of the language! In practice, it is the compiler

vendors that supply the preprocessors, but in theory, compilers and preprocessors are not related.

Lately, compiler vendors have relaxed the rule: The '#' does not have to be the first character on the

line, but it should be the first nonblank character.

Listing 2.1 uses two #include preprocessor directives. The #include directive causes direct text

substitution: The preprocessor fetches the whole file whose name is specified as the directive

argument and replaces the directive by the contents of the file taken verbatim. This can be used to

combine several source files into one source file that is then compiled as a whole. The most popular

use of this directive is to include function headers that describe functions used by the source code.

The names of these header files are put in the angle brackets to indicate to the preprocessor that it

has to search for this file in the standard directory where the compiler stores its header files. For

example, the #include directives used in the first program specify two header files. The first one is

file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (47 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



needed for using the function pow(), the second one is needed for using the operator << and the

object cout. We will learn more about functions, operators, and objects later. This is just one of

the examples of the complexity of C++¡Xit is impossible to discuss even a simple program without

using components that cannot be understood without learning much more than a simple program.

#include

#include

using namespace std;



The last line in this code segment from our first program is the using namespace directive. It is

not a preprocessor directive. It instructs the compiler to recognize the code brought in by the header

files. This is a new language feature. If you are using an older compiler, it might reject these three

lines. For such a compiler, the using namespacedirective should not be used. The names of the

header file used in older code should have extension .h. Hence, the first three lines of the program

in Listing 2.1 should be replaced with the following two lines.

#include

#include



The preprocessor directives direct the preprocessor to search the compiler directory for the

include files (function pow() that computes powers of floating point numbers, object cout that

represents the standard output, i.e., the screen, and operator << that displays the values on the

monitor screen).

Other header files could describe functions that are not part of the standard library. They are

usually written by the programmers working on the project. When the names of these files are used

in the #include directives, they are enclosed in double quotes, for example,

#include "c:\work\mydef.h"



This directive directs the preprocessor to copy into the source file the contents of the file mydef.h

from directory c:\work. In this example, I am using the absolute path in the file name. This is

convenient if the source file is moved to one directory and the header file stays in another directory.

In this case, the directive does not have to be modified. Often, however, the whole directory tree for

a project is moved to another directory. When the location of the header file changes, the source

file that uses that header file has to be modified. To avoid this, programmers use relative paths in

the #include directives.

After being processed by the preprocessor, the #include directive itself disappears from the source

file and is not passed on to the compiler.

The #include directives are extremely important: The program will not compile without them.

file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (48 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



However, they are not very sophisticated: All you have to know is what function requires what

header file. The compiler help facility will assist you with that.

The definition of a constant in Listing 2.1 initializes the variable with a symbolic name PI to the

value of 3.1415926. (It is customary to use capital letters for symbolic constants to distinguish them

from variables whose values can change during program execution.) Later, the compiler will

process this line of code:

double x=PI, y=1, z;



// definitions of variables



The executable code will copy the value allocated at the address PI the location at the address x.

An alternative method to introduce the constant PI is to use the #define directive. The #define

directive is also used for text substitution: Its first argument specifies the text to be substituted, and

the second argument specifies the text to be used as the substitute. When the preprocessor finds in

the further text of the source file the symbol that corresponds to the first directive argument, it

replaces that symbol with the second directive argument. This is an example from our first C++

program:

#define



PI 3.14159266



This directive directs the preprocessor to replace every occurrence of PI with 3.1415926. When the

preprocessor processes this line of code,

{ double x=PI, y=1, z;



// definitions of variables



it passes to the compiler the following line.

{ double x=3.1415926, y=1, z;



Notice that the preprocessor removes the comments so that the compiler does not see them either.

(We will discuss comments in the next section.)

The #define directive can be used to define macros, that is, sequences of computations that are

inserted in the source code rather than a simple symbol as in the above example. Logically, they are

used in the code in the same way as functions, combining a number of operations under a single

name. Macros are faster than functions, and they are very popular in C. In C++, we use inline

functions instead of macros. This is why I will not discuss macros in further detail, even though a

few years ago you had to know how to write macros to pass as a C programmer. Macros are great

fun, but they are a source of errors that are difficult to debug.

Another important set of preprocessor directives controls conditional computations. The #ifdef

file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (49 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



directive includes the code that follows it if the symbol used with this directive is defined. The

scope of this directive is limited by the #endif directive. For example, the following code is

included in the compilation if the symbol CPLUSPLUS is defined; otherwise, the preprocessor hides

this code from the compiler because it is not needed when the program is compiled as a C program.

#ifdef CPLUSPLUS

. . .whatever is needed when the program is written in C++

#endif



Notice that the symbol does not have to have a value; the use of the symbol in a #define directive

is enough for the symbol to be defined for the purposes of the #ifdef directive. Also notice that the

symbolic names are in uppercase. It is not necessary, but it is a common programming convention.

Another popular convention is to use lowercase, but start the symbol name with two underscore

characters:

#define __cplusplus

#ifdef __cplusplus

. . .whatever is needed when the program is written in C++

#endif



Another method to indicate the scope of the #ifdef directive is to use the #else directive. The

code that follows the #else directive (until the #endif directive is found) is not included in the

computation when the code that follows the #ifdef directive is included, and vice versa. For

example,

#define MT

#ifdef MT

#define NFILE

#else

#define NFILE

#endif



40

20



This code is similar to what you find in the header files; if the symbol MT is defined, the limit for

the number of files is 40; if we remove its definition from the source file, the limit will be 20.

The #ifndef directive is opposite to the #ifdef directive. It includes the source code that follows

it (until the #else or #endif directive) only if the symbol used in that directive is not defined. If

the symbol is defined, the code that follows the #ifndef directive is skipped; if the #else directive

is present, the code that follows it (until the #endif directive) is passed on to the compiler. The

next example is again borrowed from a header file:



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (50 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



#ifndef NULL

#define NULL

#endif



0



This is a very popular technique to make sure that the symbol is defined and defined only once

even though it is repeated in several files. If this definition is found in another file again, it will be

silently ignored.

The preprocessor directives for conditional compilations are often used to support program

portability. If the application should work in several environments, and the code for the application

is basically the same for each environment with the exception of localized segments, you put these

segments inside the conditional compilation directives. When the system is ported from one

environment to another, all that it takes is to replace the #define directive for one symbol with the

#define directive for another symbol.

This sounds simple and effective. The reality is somewhat more complex, and the preprocessor

directives can be easily abused. This is why it is important to limit the use of preprocessor

directives to simple #include directives for header files. Use other directives when you become

more comfortable with the language.



Comments

C++ has two types of comments: block comments and end-of-line comments. Block comments

start with a two-character symbol '/*' and end with a two-character symbol '*/'; end-of-line

comments start with a two-character symbol '//' and end at¡Xyes, you've guessed it¡Xthe end of

line; that is, at a next newline character in the source file. The two-character symbols are quite

common in C++. Most of them are inherited from C. Using the two-character symbols for operators

and in other contexts instead of additional keywords was one of the ways the designers of C

managed to design the language with only 30 keywords (and persuaded everyone that C was indeed

a very small language).

The characters of two-character symbols (all two-character symbols in C++, not just comments)

have to be typed next to each other. They cannot be separated by white space (or, for that matter, by

any other character).

Text within comments of either type is equivalent to white space and hence is logically invisible to

the compiler; actually, it is invisible to the compiler because the preprocessor removes the

comments before the text of the source code is compiled. Here is an example of a block comment:

/* Comments are directed to a human, not to a compiler.

Any symbol could be in a comment, including tabs, new

lines, //, /*. We can format comments nicely, so that



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (51 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



the structure of the text is clear to the reader. */



Many programmers use block comments as a preface to functions or significant segments of the

algorithm. In these comments, they describe the purpose of the algorithm, input data used for

processing, output data that is the result of computations, and other functions that are called to

accomplish the task. Often, the update history is documented as well: the initial author and the date

of the first version, authors and dates of updates, and the purpose of each update. The exact format

of these block comments varies from organization to organization. It is, of course, important to

stick to an uniform format. Even more important is to stick to the habit and provide the comments.

Can anything be more important than providing comments? Sure: updating the comments when the

code changes. There are few things more detrimental to maintenance than comments that are

incorrect.

NOTE

In C, only block comments are available. If the programmer wants to comment on individual lines

of code, the block comments are used for individual lines similar to the way I did it for our first

C++ program. I think that the designers of C felt that the programmers will not be bothered by the

need to finish each line comment with a two-character symbol ' */ '.

Listing 2.2 shows our first C++ program written for an older compiler: I use the .h extension for

library header file, the #define directive instead of const, and the C-type block comments.



Example 2.2. Your first C++ program with block comments.

#include

/* preprocessor directives */

#include

#define PI 3.1415926

int main(void)

/* function returns integer */

{

double x=PI, y=1, z;

/* definitions of variables */

cout << "Welcome to the C++ world!" << endl; /* function call */

z = y + 1;

/* assignment statement */

y = pow(x,z);

/* function call */

cout << "In that world, pi square is " << y << endl;

cout << "Have a nice day!" << endl;

return 0;

/* return statement */

}

/* end of the function block */



To avoid typing useless characters, C++ designers added the end-of-line comments to the language,

which work the same way as block comments: Everything between the two-character symbol '//'

and the next end of line is invisible to the compiler.

There are two differences between the two types of comments in C++. The first one is obvious: endfile://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (52 of 1187) [8/17/2002 2:57:45 PM]



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm



of-line comments cannot span several lines, whereas block comments can; this is why block

comments were introduced into the language to begin with. This difference is significantly

mitigated (or even rendered irrelevant) by the fact that an end-of-line comment can take the whole

line.

//

//

//

//



Comments are directed to a human, not to a compiler.

Any symbol could be in a comment, including tabs, new

lines, //, /*. We can format comments nicely, so that

the structure of the text is clear to the reader.



The second difference is more subtle. The end-of-line comment can contain any character,

including other comment symbols. Its delimiter is the new line character (ASCII code 12). The

block comment can contain any character, including other comment symbols, with the exception of

the end-of-block comment symbol '*/'. In other words, block comments cannot be nested. The

preprocessor misses the nested opening symbol '/*' because it is just part of the comment; when it

finds the nested closing symbol '*/', it accepts it as the end of comment and passes the rest of the

comment (including the second closing symbol '*/') on to the compiler; the compiler gets confused

and generates misleading error messages.

/* Here, the second opening symbol /* is invisible */

and the compiler thinks the last line is no comment */



This is a manifestation of the age-old tension between programmers and compiler (and

preprocessor) designers, or rather between the size of the tools we use and their intelligence. The C

language (and its successor C++) favors tool designers. After all, every programmer is told that

nesting of block comments is not allowed. So, when the error occurs, the programmer should be

able to figure out what is going on easily.

Why do programmers want to use nested comments? Often, we would like to experiment with

some alternative version of the code, especially when we are not sure how it works. Let us look at

our first C++ program as an example. What should we do if we want to see how it works without

three lines in the middle? The simplest way to achieve that is to comment this code out. Listing 2.3

shows how our example looks now:



Example 2.3. Your first C++ program with code blocked out.

#include

/* preprocessor directives */

#include

#define PI 3.1415926

int main(void)

/* function returns integer */

{

double x=PI, y=1, z;

/* definitions of variables */

cout << "Welcome to the C++ world!" << endl; /* function call */

/* beginning of the block to be cut out



file://///Administrator/General%20English%20Learning/it2002-7-6/core.htm (53 of 1187) [8/17/2002 2:57:45 PM]



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 2. Getting Started Quickly: A Brief Overview of C++

Tải bản đầy đủ ngay(0 tr)

×