• No results found

Functions, Namespaces and Introduction to Inheritance

7.2 FUNCTIONS AND FUNCTION POINTERS

Functions, Namespaces and Introduction to Inheritance

7.1 INTRODUCTION AND OBJECTIVES

We introduce three new C++ concepts in this chapter. First, we discuss how to model functions and we introduce the so-calledfunction pointer mechanism. This feature is important in the current book because much of our work involves defining functions that implement algorithms.

Second, we introduce thenamespace mechanism. A namespace is used to group logically related C++ code. You can place almost anything in a namespace. Namespaces can be nested.

Finally, we introduce the concept of inheritance. In particular, we discuss how to share common functionality between similar classes and we do this by defining a so-calledbase class that we can specialise by definingderived classes.

Having understood the C++ theory in this chapter you will be in a position to apply the knowledge to financial engineering applications. In order to keep the material relevant to your domain we have developed a number of examples and test cases:

r

Defining function pointers and using them as class members. In this way we can create flexible code by allowing member functions to switch between different functionality

r

Grouping related functions in namespaces and using namespaces in financial engineering applications

r

Basic examples of inheritance: we avoid all examples that have to do with dogs, cats and other kinds of hierarchies. Instead, we give examples that are of direct relevance to the current domain. In this case, we introduce several non-linear solvers such as the Bisection method and the Newton-Raphson method. Each specific solver will be implemented as a C++ class

r

We can use the above solvers to solve problems related to volatility estimation (Haug, 1998), fixed income problems (Fabozzi, 1993) and finding the roots of polynomials (Scheid, 1968)

To summarise, this chapter introduces a number of mechanisms that promote code reusability, understandability and reliability.

7.2 FUNCTIONS AND FUNCTION POINTERS

In this section we show how to work with functions and function pointers in C++. A function pointer is defined on the stack and it can be assigned to a real function at run-time. The advantage is clear: no hard-coded functions in client code but run-time switching ability.

We also discuss the applications of functions and function pointers to financial engineering in this section. A more detailed discussion can be found in Duffy (2004).

93

7.2.1 Functions in financial engineering

A significant part of financial engineering involves defining functions that do something of relevance in this domain. One reason why writing C++ software for this domain is so difficult is that the functions must satisfy stringent requirements. For example, we can think of the following features that we would like to support:

r

A function may have one, two and n-dimensional equivalents

r

The number of input arguments to a function may be variable

r

The return type of a function may be a scalar or a vector quantity

r

The return types can be real-valued or complex-valued, for example

r

It must be possible to replace the code that implements a function by another block of code (this is called aStrategy pattern)

These are not the only requirements that may be desired in an application but they do give an indication of the challenges that we must surmount in our applications. In this chapter we shall resolve some of these using ‘standard’ C++ while in later chapters we shall see how the Standard Template Library (STL) and Design Patterns enable us to define classes that realise the above requirements.

7.2.2 Function categories

We now discuss what functions are from a mathematical point of view.

Afunction (or mapping) f between elements of a space D (called the domain of f ) and a spaceR (called the range of f ) is an association in which each value of a variable x in D is mapped to one and only one variabley in R. A function is a particular kind of relation and we can then view the function as a set of ordered pairs (x, y) with x in D and y in R.

A common notation for a function f from D to R is

f : D→ R (7.1)

Functions can be composed. For example, suppose f is a mapping from D to R1 and g is a mapping fromR1 to R2 then the composition of g and f is defined by

(g f )(x)= g( f (x)) for all x in D (7.2) Notice that the range of the composed mappingg f is R2.

In equation (7.1) we have not said anything about the structure or ‘texture’ of the spacesD andR. For example, these spaces may be continuous or discrete, deterministic, fuzzy and so on. We concentrate in this chapter on deterministic functions only and the possible kinds of mappings are:

G1: Continuous to continuous G2: Continuous to discrete G3: Discrete to continuous G4: Discrete to discrete

In order to reduce the scope even further we distinguish between the following kinds of functions:

r

Scalar-valued function (maps a double to a double, for example)

r

Vector function (maps a double into a vector)

r

Real-valued function (maps a vector into a double)

r

Vector-valued function (maps a vector into a vector)

Ascalar-valued function takes a single scalar argument as input and produces a single scalar result as output. Avector function takes a scalar as input and produces a vector as output. Thus, a vector function can be seen as an array of scalar-valued functions. Areal-valued function accepts a vector as input and produces a double as output. Finally, avector-valued function accepts a vector as input and produces a vector result as output.

In this chapter we concentrate on scalar-valued and real-valued functions. Of course, it is not difficult to define the equivalent complex-valued functions.

7.2.3 Modelling functions in C++

In this section we discuss function pointers and we give an example to show how they work. In general, pointers to functions can be assigned, placed in arrays, passed to functions, returned by functions, and so on.

We declare a function pointer by defining its input arguments, return type and its name by using pointer arithmetic. We now give an example of a function declaration with an embedded function pointer:

void genericFunction (double myX, double myY,

double (*f) (double x, double y)) {

// Call the function f with arguments myX and myY double result = (*f)(myX, myY);

cout << "Result is: " << result << endl;

}

This is the declaration of a function called genericFunction. It is a specific function (that is, it is not a function pointer) and it accepts arguments myX and myY that will be passed to the function pointer f. You can then call genericFunction by giving any two arguments and a specific function that has two arguments of type double and whose return type is a double, for example the following:

double add(double x, double y) {

cout << "** Adding two numbers: " << x << ", " << y << endl;

return x + y;

}

double multiply(double x, double y) {

cout << "** Multiplying two numbers: " << x << ", " << y << endl;

return x * y;

}

double subtract(double x, double y) {

cout << "** Subtracting two numbers: " << x << ", " << y << endl;

return x - y;

}

The advantage of using function pointers is that functions using them are not hard-wired into specific functions but a primitive form ofpolymorphism is offered. We shall introduce this topic when we discuss the C++ inheritance mechanism in detail.

Continuing with the above example, we define the basic operations for addition, multipli-cation and subtraction and these functions will be called from genericFunction. We now show how this is done by giving the source code. We call genericFunction three times from the main() program:

7.2.4 Application areas for function pointers, part I

We give a short discussion of where function pointers can be of use in numerical analysis and financial engineering. Later chapters will elaborate on these issues:

r

As members of classes: we can declare a function pointer as a (private or public) member of a class. We can then call this function from the member functions of the class

r

Any function func() can contain a function pointer as formal parameter. Client code can then call function func() with the function pointer assigned to a specific function, as the code in section 7.2.3 has shown

r

It is possible to define ‘global’ functions (here we mean non-member functions) that contain function pointers as formal arguments and can be used by function pointers in an assignment statement. This is an example of procedural programming and it can be useful because it is not mandatory to define classes to achieve a similar effect. In short, they reduce cognitive overload

We shall elaborate on these issues in the coming chapters.