Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Visual C++ 2005 (2006) [eng]

.pdf
Скачиваний:
125
Добавлен:
16.08.2013
Размер:
18.66 Mб
Скачать

Introducing Structure into Your Programs

Exercises

You can download the source code for the examples in the book and the solutions to the following exercises from http://www.wrox.com.

1.The factorial of 4 (written as 4!) is 4*3*2*1 = 24, and 3! is 3*2*1 = 6, so it follows that 4! = 4*3!, or more generally:

fact(n) = n*fact(n – 1)

The limiting case is when n is 1, in which case 1! = 1. Write a recursive function which calculates factorials, and test it.

2.Write a function that swaps two integers, using pointers as arguments. Write a program that uses this function and test that it works correctly.

3.The trigonometry functions (sin(), cos() and tan()) in the standard math library take arguments in radians. Write three equivalent functions, called sind(), cosd() and tand(), which takes arguments in degrees. All arguments and return values should be type double.

4.Write a native C++ program that reads a number (an integer) and a name (less than 15 characters) from the keyboard. Design the program so that the data entry is done in one function, and the output in another. Keep the data in the main program. The program should end when zero is entered for the number. Think about how you are going to pass the data between functions_by value, by pointer, or by reference?

5.(Advanced) Write a function that, when passed a string consisting of words separated by single spaces, returns the first word; calling it again with an argument of NULL returns the second word, and so on, until the string has been processed completely, when NULL is returned. This is a simplified version of the way the native C++ run-time library routine strtok() works. So, when passed the string ‘one two three’, the function returns you ‘one’, then ‘two’, and finally ‘three’. Passing it a new string results in the current string being discarded before the function starts on the new string.

269

6

More about Program

Structure

In the previous chapter, you learned about the basics of defining functions and the various ways in which data can be passed to a function. You also saw how results are returned to a calling program.

In this chapter, we will explore the further aspects of how functions can be put to good use, including:

What a pointer to a function is

How to define and use pointers to functions

How to define and use arrays of pointers to functions

What an exception is and how to write exception handlers that deal with them.

How to write multiple functions with a single name to handle different kinds of data automatically

What function templates are and how you define and use them

How to write a substantial native C++ program example using several functions

What generic functions are in C++/CLI

How to write a substantial C++/CLI program example using several functions

Pointers to Functions

A pointer stores an address value that, up to now, has been the address of another variable with the same basic type as the pointer. This has provided considerable flexibility in allowing you to use different variables at different times through a single pointer. A pointer can also point to the address of a function. This enables you to call a function through a pointer, which will be the function at the address that was last assigned to the pointer.

Chapter 6

Obviously, a pointer to a function must contain the memory address of the function that you want to call. To work properly, however, the pointer must also maintain information about the parameter list for the function it points to, as well as the return type. Therefore, when you declare a pointer to a function, you have to specify the parameter types and the return type of the functions that it can point to, in addition to the name of the pointer. Clearly, this is going to restrict what you can store in a particular pointer to a function. If you have declared a pointer to functions that accept one argument of type int and return a value of type double, you can only store the address of a function that has exactly the same form. If you want to store the address of a function that accepts two arguments of type int and returns type char, you must define another pointer with these characteristics.

Declaring Pointers to Functions

You can declare a pointer pfun that you can use to point to functions that take two arguments, of type char* and int, and return a value of type double. The declaration would be as follows:

double (*pfun)(char*, int);

// Pointer to function declaration

At first you may find that the parentheses make this look a little weird. This statement declares a pointer with the name pfun that can point to functions that accept two arguments of type pointer to char and of type int, and return a value of type double. The parentheses around the pointer name, pfun, and the asterisk are necessary; without them, the statement would be a function declaration rather than a pointer declaration. In this case, it would look like this:

double *pfun(char*, int);

//

Prototype

for a function

 

//

returning

type double*

This statement is a prototype for a function pfun() that has two parameters, and returns a pointer to a double value. Because you intended to declare a pointer, this is clearly not what you want at the moment.

The general form of a declaration of a pointer to a function looks like this:

return_type (*pointer_name)(list_of_parameter_types);

The pointer can only point to functions with the same return_type and list_of_parameter_types specified in the declaration.

This shows that the declaration of a pointer to a function consists of three components:

The return type of the functions that can be pointed to

The pointer name preceded by an asterisk to indicate it is a pointer

The parameter types of the functions that can be pointed to

If you attempt to assign a function to a pointer that does not conform to the types in the pointer declaration, the compiler generates an error message.

272

More about Program Structure

You can initialize a pointer to a function with the name of a function within the declaration of the pointer. The following is an example of this:

long

sum(long num1, long

num2);

//

Function prototype

long

(*pfun)(long, long)

= sum;

//

Pointer to function points to sum()

In general you can set the pfun pointer that you declared here to point to any function that accepts two arguments of type long and returns a value of type long. In the first instance you initialized it with the address of the sum() function that has the prototype given by the first statement.

Of course, you can also initialize a pointer to a function by using an assignment statement. Assuming the pointer pfun has been declared as above, you could set the value of the pointer to a different function with these statements:

long product(long, long);

// Function prototype

...

 

pfun = product;

// Set pointer to function product()

As with pointers to variables, you must ensure that a pointer to a function is initialized before you use it to call a function. Without initialization, catastrophic failure of your program is guaranteed.

Try It Out

Pointers to Functions

To get a proper feel for these newfangled pointers and how they perform in action, try one out in a program.

// Ex6_01.cpp

// Exercising pointers to functions #include <iostream>

using std::cout; using std::endl;

long sum(long a, long b);

// Function prototype

long product(long a, long b);

// Function prototype

int main(void)

 

{

 

long (*pdo_it)(long, long);

// Pointer to function declaration

pdo_it = product;

 

cout << endl

 

<< “3*5 = “ << pdo_it(3, 5);

// Call product thru a pointer

pdo_it = sum;

// Reassign pointer to sum()

cout << endl

 

<< “3*(4 + 5) + 6 = “

<< pdo_it(product(3, pdo_it(4, 5)), 6); // Call thru a pointer, // twice

cout << endl; return 0;

273

Chapter 6

}

//Function to multiply two values long product(long a, long b)

{

return a*b;

}

//Function to add two values long sum(long a, long b)

{

return a + b;

}

This example produces the output:

3*5 = 15 3*(4 + 5) + 6 = 33

How It Works

This is hardly a useful program, but it does show very simply how a pointer to a function is declared, assigned a value, and subsequently used to call a function.

After the usual preamble, you declare a pointer to a function, pdo_it, which can point to either of the other two functions that you have defined, sum() or product(). The pointer is given the address of the function product() in this assignment statement:

pdo_it = product;

You just supply the name of the function as the initial value for the pointer and no parentheses or other adornments are required. The function name is automatically converted to an address, which is stored in the pointer.

The function product() is called indirectly through the pointer pdo_it in the output statement.

cout <<

endl

 

<<

“3*5 = “ << pdo_it(3, 5);

// Call product thru a pointer

You use the name of the pointer just as if it was a function name, followed by the arguments between parentheses exactly as they would appear if you were using the original function name directly.

Just to show that you can do it, you change the pointer to point to the function sum().

pdo_it = sum;

// Reassign pointer to sum()

You then use it again in a ludicrously convoluted expression to do some simple arithmetic:

cout << endl

<<“3*(4 + 5) + 6 = “

<<pdo_it(product(3, pdo_it(4, 5)), 6); // Call thru a pointer,

//twice

This shows that a pointer to a function can be used in exactly the same way as the function that it points to. The sequence of actions in the expression is shown in Figure 6-1.

274

More about Program Structure

pdo_it ( product ( 3 , pdo_it ( 4 , 5 ) ) , 6)

equivalent to

sum ( 4 , 5 )

results in

product ( 3 , 9 )

results in

pdo_it ( 27 , 6 )

equivalent to

sum ( 27 , 6 )

produces

33

Figure 6-1

A Pointer to a Function as an Argument

Because ‘pointer to a function’ is a perfectly reasonable type, a function can also have a parameter that is a pointer to a function. The function can then call the function pointed to by the argument. Because the pointer can be made to point at different functions in different circumstances, this allows the particular function that is to be called from inside a function to be determined in the calling program. In this case, you can pass a function explicitly as an argument.

Try It Out

Passing a Function Pointer

You can look at this with an example. Suppose you need a function that processes an array of numbers by producing the sum of the squares of each of the numbers on some occasions, and the sum of the cubes on other occasions. One way of achieving this is by using a pointer to a function as an argument.

//Ex6_02.cpp

//A pointer to a function as an argument #include <iostream>

using std::cout; using std::endl;

//Function prototypes

double squared(double); double cubed(double);

275

Chapter 6

double sumarray(double array[], int len, double (*pfun)(double));

int main(void)

{

double array[] = { 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5 }; int len = sizeof array/sizeof array[0];

cout << endl

<<“Sum of squares = “

<<sumarray(array, len, squared);

cout << endl

<<“Sum of cubes = “

<<sumarray(array, len, cubed);

cout << endl; return 0;

}

//Function for a square of a value double squared(double x)

{

return x*x;

}

//Function for a cube of a value double cubed(double x)

{

return x*x*x;

}

//Function to sum functions of array elements

double sumarray(double array[], int len, double (*pfun)(double))

{

double total = 0.0;

// Accumulate total in here

for(int i = 0; i < len; i++) total += pfun(array[i]);

return total;

}

If you compile and run this code, you should see the following output:

Sum of squares = 169.75

Sum of cubes = 1015.88

How It Works

The first statement of interest is the prototype for the function sumarray(). Its third parameter is a pointer to a function that has a parameter of type double, and returns a value of type double.

double sumarray(double array[], int len, double (*pfun)(double));

276

More about Program Structure

The function sumarray() processes each element of the array passed as its first argument with whatever function is pointed to by its third argument. The function then returns the sum of the processed array elements.

You call the function sumarray() twice in main(), the first time with the function name squared as the third argument, and the second time using cubed. In each case, the address corresponding to the function name that you use as the argument is substituted for the function pointer in the body of the function sumarray(), so the appropriate function is called within the for loop.

There are obviously easier ways of achieving what this example does, but using a pointer to a function provides you with a lot of generality. You could pass any function to sumarray() that you care to define as long as it takes one double argument and returns a value of type double.

Arrays of Pointers to Functions

In the same way as with regular pointers, you can declare an array of pointers to functions. You can also initialize them in the declaration. Here is an example of declaring an array of pointers.

double sum(double, double);

// Function

prototype

double product(double, double);

// Function

prototype

double difference(double, double);

// Function prototype

double (*pfun[3])(double,double) =

 

 

{ sum, product, difference };

// Array of function pointers

 

 

 

Each of the elements in the array is initialized by the corresponding function address appearing in the initializing list between braces. To call the function product() using the second element of the pointer array, you would write:

pfun[1](2.5, 3.5);

The square brackets that select the function pointer array element appear immediately after the array name and before the arguments to the function being called. Of course, you can place a function call through an element of a function pointer array in any appropriate expression that the original function might legitimately appear in, and the index value selecting the pointer can be any expression producing a valid index value.

Initializing Function Parameters

With all the functions you have used up to now, you have had to take care to provide an argument corresponding to each parameter in a function call. It can be quite handy to be able to omit one or more arguments in a function call and have some default values for the arguments that you leave out supplied automatically. You can arrange this by initializing the parameters to a function in its prototype.

For example, suppose that you write a function to display a message, where the displayed message is passed as an argument. Here is the definition of such a function:

277

Chapter 6

void showit(const char message[])

{

cout << endl

<< message; return;

}

You can initialize the parameter to this function by specifying the initializing string value in the function prototype, as follows:

void showit(const char message[] = “Something is wrong.”);

Here, the parameter message is initialized with the string literal shown. If you initialize a parameter to a function in the prototype, if you leave out that argument when you call the function, the initializing value is used in the call.

Try It Out

Omitting Function Arguments

Leaving out the function argument when you call the function executes it with the default value. If you supply the argument, it replaces the default value. You can use the showit() function to output a variety of messages.

//Ex6_03.cpp

// Omitting function arguments #include <iostream>

using std::cout; using std::endl;

void showit(const char message[] = “Something is wrong.”);

int main(void)

{

const char mymess[] = “The end of the world is nigh.”;

showit();

// Display the basic message

showit(“Something is terribly wrong!”);

// Display an alternative

showit();

// Display the default again

showit(mymess);

// Display a predefined message

cout << endl;

 

return 0;

 

}

 

void showit(const char message[])

 

{

 

cout << endl

 

<< message;

 

return;

 

}

 

278