C to Cpp

advertisement
C++ extensions to C
In this subsection, we shall briefly discuss some of the useful, non-object-orientated
extensions to C introduced in the C++ language. Files containing source code which
incorporates C++ elements should be distinguished from files containing plain C code
via the extension .cpp.
In C, all local variables within a function must be declared before the first executable
statement. In C++, this restriction is relaxed: a local variable can be declared (almost)
anywhere in a function, provided that this declaration occurs prior to the variable's
first use. The following code snippet illustrates the use of this new feature:
. .
for
{
.
}
. .
.
(int i = 0; i < MAX; i++)
. .
.
Observe that the index i of the for loop is now declared at the start of the loop,
instead of at the start of the function containing the loop. This is far more convenient,
and also makes the code easier to read (since we no longer have to skip back to the
declarations at the start of the function to check that i is an int). Note, however, that
the variable i is only defined over the extent of the loop (i.e., between the curly
braces). Any attempt to reference i outside the loop will result in a compilation error.
In general, when a variable is declared in C++ its scope (i.e., range of definition)
extends from its declaration to the closing curly brace which terminates the current
program block. Program blocks are functions, loops, conditionally executed
compound statements, etc., and are delineated by curly braces. There are a number of
restrictions to this new method of variable declaration. Variables cannot be declared
within conditional statements, in the second or third expressions of for loops, or in
function calls.
In C, we have seen that in order to pass an argument to a function in such a manner
that changes made to this argument within the function are passed back to the calling
routine, we must actually pass a pointer to the argument. This procedure, which is
called passing by reference, is illustrated in the code snippet listed below:
. . .
void square(double, double *);
. . .
int main()
{
. . .
double arg, res;
square(arg, &res);
. . .
return 0;
}
. . .
void square(double x, double *y)
{
*y = x * x;
return;
}
Here, the second argument to square() is returned to main() in modified form. This
argument must, therefore, be passed as a pointer. Consequently, we must write &res,
rather that res, when calling square(), and we must refer to the argument as *y, rather
than y, in the function itself. After a while, all these ampersands and asterisks can
become a little tedious! C++ introduces a new method of passing by reference which
somewhat less involved. This new method is illustrated in the following:
. . .
void square(double, double &);
. . .
int main()
{
. . .
double arg, res;
square(arg, res);
. . .
return 0;
}
. . .
void square(double x, double &y)
{
y = x * x;
return;
}
Here, the second argument to square() is again passed by reference. However, this is
now indicated by prepending an ampersand to the variable name in the function
declaration. A corresponding ampersand appears in the associated function prototype.
Note that we do not need to explicitly pass a pointer to the second argument when
calling square() (this is done behind the scenes): i.e., we write res, rather than &res,
when calling square(). Likewise, we do not have to explicitly deference the argument
in the function itself (this is also done behind the scenes): i.e., we refer to the
argument by its regular local name, y, as opposed to *y, within the function.
Functions are used in C programs to avoid having to repeat the same block of code in
many different places in the source. The use of functions also renders a code easier to
read and maintain. However, there is a price to pay for the convenience of functions.
When a regular function is called in an executable, the program jumps to the block of
memory in which the compiled function code is stored, and then jumps back to its
original position in memory space when the function returns. Unfortunately, the large
jumps in memory space associated with a function call take up a non-negligible
amount of CPU time. Indeed, the overhead associated with making function calls
often discourages scientific programmers from writing small functions, even when it
may be desirable to do so. C++ provides a way out of this dilemma, via the use of the
new keyword inline. An inline function looks like a normal function when it is used,
but is compiled in a different manner. Calling an inline function from several different
locations in a code does not result in multiple calls to a single function. Instead, the
code for the inline function is inserted into the program code by the compiler
wherever the function is used.
Inline functions are only useful for small functions. The disadvantage of inserting the
code for a large function multiple times into the code for a typical program easily
outweighs the small gain in performance obtained by the elimination of standard
function calls. The break-even point for inline functions is usually about three
executable lines.
To inline a function, a programmer adds the keyword inline at the start of the
function's definition. For example:
inline double square(double x)
{
return x * x;
}
Because the body of an inline function must be known before the compiler can insert
it into the program code, wherever the function is used, we must define such a
function prior to its first use--a prototype declaration is not enough. It is common
practice to define inline functions at the same location in source code files that the
prototypes for regular (i.e., outline) functions are placed.
Variable size array declarations of the form
void function(n)
{
int n;
double x[n];
. . .
}
are illegal in C, which is extremely inconvenient. In C++, such declarations are
enabled via the use of the new keywords new and delete. Thus, the C++
implementation of the above code snippet takes the form:
void function(n)
{
. . .
int n;
double *x = new double[n];
. . .
x[i] = . . .
. . .
. . .
delete x[];
. . .
}
Note that x is actually declared as a pointer, rather than a standard array. The
declaration new double[n] reserves a memory block which is just large enough to
store n doubles, and then returns the address of the start of this block. The line delete
x[] frees up the block of memory associated with the array x when it is no longer
needed (note that this is not done automatically). Unfortunately, the new and delete
keywords cannot be used to make variable size multi-dimensional arrays.
Richard Fitzpatrick 2006-03-29
Download