• No se han encontrado resultados

PARTE 2: ESTADO DE LA CUESTIÓN

4.2 Ejemplos de empresas privadas

It may seem a little odd to start at the end as it were. However that is almost always where programmers start the design of a function. We think about how we want to use it. In other words, ‘‘What should it do?’’ and ‘‘What will it need?’’ When we call a function to draw a cross in a Playpen we will wish to provide:

• Information about who ‘‘owns’’ the Playpen.

• Details of the cross such as where to start the crosspiece and how many pixels make it up, where to start the upright and how many pixels that is made of.

We will also need to think of a good name for the function, preferably one that does not need

comments to explain it. Less obviously we will have to decide what the program gets back from the function. All normal functions in programming return something even if we promptly ignore it. However in the case of this task I am going to ignore that requirement for now (but not for long, because I will have to deal with that when I come to the declaration).

Typically I might want to write something like:

int main(){ playpen paper; int const left_x(-5); int const left_y(0); int const width(11); int const bottom_x(0); int const bottom_y(-6); int const height(11);

draw_a_cross(paper, left_x, left_y,

width, bottom_x, bottom_y, height, black); cout << "Press RETURN to end";

cin.get(); }

Before we look at the last statement (the call of thedraw_a_crossfunction) a word about the previous seven statements. The first of those declarespaperto be the name of aplaypenobject. It also has the effect of creating aplaypenobject of that name (i.e. it is also a definition; that is normal for objects: declarations are also definitions). The remaining six statements declare (and define) the names of six integers with fixed values; that is the significance of theconstin each declaration (and definition – in future I will assume that define subsumes declare and definition subsumes declaration). The result is thatleft_xbecomes a name for

−5,left_ya name for 0 and so on. Remember the ‘‘magic numbers’’ mentioned in Chapter 1? We always try to give descriptive names to the numbers we use. The technique I have used in the above code is common among competent programmers.

We want to draw a cross in the window belonging to theplaypen(remember that is the general type) object calledpaper(and that is a name referring to a specific object of that type; think of the difference between dog – a class of animals – and Fido, a specific dog). The upright is to start at(bottom_x, bottom_y)and haveheightpixels (screen points), the crosspiece to start at(left_x, left_y)and have

widthpixels. And we want the drawing done in black. Or, if I am happy with a few magic numbers:

draw_a_cross(paper, -5, 0, 11, 0, -6, 11, 0);

That should give you a good idea as to why we prefer to use named values even if it does make our source code lengthier and so take longer to type in. Even if you do not agree now, try to read your code written in this way a month from now and see if you still feel that way.

Now we have a typical use, let us see how we can tell a compiler that there will be a function called

draw_a_crossthat can use the information we provide.

Declaring a function

Here we have to think about what our function will hand back to the program.draw_a_crossis a function that has no obviously useful data to give back – we are only interested in what it does. Because the rules of C++(along with many other programming languages) require that a function has some form of return, the designers of C++invented a very special type calledvoid(as it is a C++keyword, Quincy will display it in

blue). This type can be used anytime we want to specify that a function willnothave a useable return value. In other words avoidreturn type says that the function does not hand back anything when it ends. So we can start our declaration:

void draw_a_cross

We must next list the types of data that will be used by the function (the ingredients of the recipe). This list is called a parameter list. It is a list of types in the order in which the caller will provide the data. The parameters are separated by commas and placed inside parentheses. We could write it like this:

void draw_a_cross(fgw::playpen &, int, int, int, int, int, int, fgw::hue)

However if we do so, we have magic again. We would have to add a bundle of comments to explain those sixintparameters. Once you know thatfgw::hueis the type used for palette codes andfgw::playpen is a type for handling a Playpen object, we probably do not need comments to explain those two parameters. (I will remind you about the&in a moment.) Note that bothhueandplaypenhave been qualified with the library to which they belong. You should always use the full names in declarations because we normally place declarations in header files (more about these shortly). Never (until you are an expert) write ausing directive in the header file.

Rather than litter our code with comments we take advantage of the grammar (language rules) of C++ that allows us to provide a name for each parameter. These parameter names in a function declaration just document what the parameters are; in a declaration they have no other significance. We should make a special effort to choose names that document the parameters. Here is my second version of a declaration for thedraw_a_crossfunction:

void draw_a_cross(fgw::playpen &,

int left_of_cross_piece_x, int left_of_cross_piece_y, int width_cross_piece_bar,

int bottom_of_upright_x, int bottom_of_upright_y, int height_of_upright,

fgw::hue);

Some authorities would advocate naming all the parameters; that is not my style. I focus on the parameters that need to be documented because the type’s name is not enough.

Note the semicolon at the end; that tells the compiler that this is just a function declaration andnota definition as well (we will get to the definition in the next section).

Now here is a further explanation of the&. From the perspective of the user of the function, it stands as a warning that the function will access the original data and so may be able to change it. In this case that is exactly what we want. We want the function,draw_a_cross, to change theplaypenobject so that it displays a cross in the Playpen. There is sometimes an additional benefit because data provided to an&parameter (called a reference parameter) will not be copied. This ‘‘do not copy’’ behavior matters for large objects (for example aplaypenobject uses over a quarter of a megabyte of RAM) where copying can use valuable space and also take time. It is also important because some objects cannot be copied (for example, you cannot copystd::cout).

Notice that it is the function designer’s job to decide whether a reference parameter is desirable or not. The user of the function is only concerned if they have something that must not be changed. The use of a plain reference parameter in a declaration warns the caller that the object passed to the function may be changed by it. It also means that the compiler can provide some protection by refusing code that tries to hand over aconstqualified object (i.e. one that the programmer has specified as immutable) to a function declared with a plain reference.

Documento similar