C++ coursework module - Information Engineering Main/Home...

40
C++ coursework module I. Reid, B. Tordoff, E. Sommerlade Department of Engineering Science University of Oxford Trinity Term 2009 1

Transcript of C++ coursework module - Information Engineering Main/Home...

C++ coursework module

I. Reid, B. Tordoff, E. SommerladeDepartment of Engineering Science

University of Oxford

Trinity Term 2009

1

Introduction to C++ 2

1 Getting started

• Before you log on, make sure you will log on to the ENG domain, which should beshown in the last text box of the login dialog.

• Now log on! [Use your Lab username and password]. A successful log-in should landyou in Windows XP.

• Start Windows Explorer [Start menu→My Computer] and check that the drives ”U:”and ”H:” are there. If not, contact a demonstrator or technical support.

• In Windows Explorer, navigate to U:\C++ cwm. Double click the script file startup.bat,which will copy a directory called CXXCWM into your home directory. It will further-more start an instance of Visual Studio, which can take a while. Use this time toexplore the newly created folder.

• Navigate to H:\CXXCWM and make sure there are the directories build and src. Theformer contains all the compilation results, and can easily become cluttered. The srcdirectory is for the source files. Whenever a reference to source files is made in thisdocument, they are expected to live in this directory or below.

• Whenever you have to log on to the system again or leave Visual Studio, navigate toH:\CXXCWM and double click the vs.bat file, which will start Visual Studio with theright settings.

• After the setup, you will be left with the Visual Studio integrated development envi-ronment (IDE). More on this later.

2 Introduction

As you know, a computer program is a sequence of instructions (written in a “language”)which implements an algorithm (or set of algorithms) to process some data. The well-known Swiss computer scientist, Nicholas Wirth, summed this up in the title of his 1970sseminal book “Algorithms + Data Structures = Programs”.

You should all be familar (to a greater or lesser degree) with matlab from your course-work last year. matlab is an interpreted language; each line of code gets decoded andconverted to some action by the computer in turn. In contrast, C and C++ are com-piled languages, meaning you write code into an editor, then run another program called acompiler on the file contents to convert it into machine- readable form called an executable.

Another immediate significant difference between Matlab and C/C++ is that C andC++ are strongly-typed languages. This means that all data must be explicitly declaredprior to use, and that each variable has an explicit type. Contrast this with Matlab in whichevery variable is assumed to be a real number or a matrix of real numbers, and a new variablecan simply be created by assigning a value to it.

In C/C++ you need to decide what sort of data you want to store in a variable, andthe language provides a set of atomic predefined types which include char, int, floatand double. These simple data types can be used on their own, or they can be used as thebasic building blocks of more complex compound data structures (see below).

Introduction to C++ 3

2.1 Functions and arguments

In C the concept of a function is fundamental, and hopefully you remember what a functionis from 1st year matlab. It is a block of related code which accepts some input data (itsparameters or arguments), does some work (an implementation of an algorithm), and returnsan answer – its return value(s). Once written and debugged, it can be thought of a blackbox whose precise internal workings need not be understood. To use it, a programmer needonly know something about what it is trying to achieve, what values to give it, and what toexpect in return.

For example, consider the definition of the cos function which is provided as part of thesystem:

double cos(double x);

Presumably it works by truncating a Taylor Series to some degree of precision, but asapplication programmers we don’t need to know the details. All we need to know is thatwe should pass it an angle, specified in radians using a double, and expect a double inreturn. The implementation of the function has been encapsulated and the definition, orfunction prototype tells us most of what we need to know providing we get to grips withthe differences between matlab and C syntax. Here the first keyword, double indicatesthat the type of the return value is a double-precision floating point number, cos fairlyobviously is the function name, and double x indicates that the function accepts oneinput parameter which must be a double-precision real number whose local name is x.

In order to use this function, somewhere in our code we would have a line like

double y = cos(1.159);

or

double ang = 1.159;double y = cos(ang);

Note the distinction between the formal parameter x which is the name within thefunction cos (and has scope only within that function), and the actual parameter whichin the first case the constant value 1.159 and in the second is the variable ang.

When writing a C program, one typically spends a good deal of design time breakingthe program into smaller functional units, and then refining these, possibly into smallerfunctions, etc. These smaller components can hopefully be debugged independently: thedesign is thus top-down, but the implementation (the explicit coding) is bottom-up.

2.2 C++

C++ is a development of C incorporating a number of very useful design elements, andnecessitating some different approaches to program design. C++ is a so-called object-oriented language. Although it retains all the basic features of C, including functions,the emphasis on design shifts away from functions to data structures. In particular C++introduces the idea of a class, which is a way of encapsulating related data and functionstogether into one “unit”. This style of programming helps with the problems associatedwith teams of programmers working on different aspects of one large system, and for thisreason it has become very popular in “the real world”.

Introduction to C++ 4

2.3 Texts

• C++ primer by Lippman and Lajoie [Addison-Wesley]. Unfortunately rather toocomprehensive to be a real primer, so use it as a work of reference, in conjunction withthese notes.

• C++ Distilled by Ira Pohl [Addison-Wesley]. A simpler introduction to C++.

• The C++ Programming Language by Stroustrup [Addison-Wesley] For the very keen,this is the C++ programmer’s bible (Bjarne Stroustrup invented the language), butis probably a little obtuse for beginners.

• Effective C++ by Scott Meyers [Addison-Wesley]. Once you got started with C++,this book shows you how to do a lot of things right.

• These COURSE notes are available on line (HTML and pdf) at:U:\C++ cwm\doc\index.html. The lecture overheads are also available in the sameplace. Documentation for the graphics library used later in the course is also found inthe doc directory, and can be accessed through said html file.

• Documentation from Microsoft on the C++ run-time library is a bit difficult to find:http://msdn.microsoft.com/en-us/library/634ca0c2(VS.80).aspx bet-ter is the following version: http://www.cplusplus.com/reference/clibrary

2.4 Format and Objectives

The coursework module will consist of a series of exercises, to build up your skills in C++programming, followed by a project. Exercises and tasks are marked with a screen-and-keyboard symbol:

The course covers a lot of ground very rapidly. The exercises build up in complexity, andthe course notes deliberately reduce the amount of help given as we go on. Demonstratorsare on hand while you are working — don’t hesitate to ask them for help, including expla-nations of revision topics. You therefore have several resources available: online man-pages,these notes, the lecture overheads, the course books spread throughout the lab, and thedemonstrators. Use all of these freely, but wisely.

The final part of the module will allow you certain freedom to develop your own ideaswithin the context of a graphical computer game application: navigating through a labyrinth.More on this later.

In terms of the learning objectives, within a day or two, we should cover the followingconcepts, either explicitly or in passing:

• functions, arguments and return values (revision)

• function prototypes

• formal vs actual parameters

Introduction to C++ 5

• classes

• private vs public data and methods

• encapsulation

• program organisation (header and source files, program modules)

• input/output

• constructor and accessor methods, copy constructors

• parameter passing by reference

• operators, function and operator overloading

• inheritance

• recursion

More generally, it is to be hoped that in the course of the module you learn somethingnot just about C++, but about sound computer program design, coding and management,concepts which apply whatever the language.

Different people will inevitably work at different rates, but below is a rough guide towhere you should be when. If you feel like you are well ahead of this you should make sureyou do more optional exercises and talk to demonstrators about enhancing the challengepresented by the exercises (any of the demonstrators will also be happy to talk to you abouttopics not covered in this course, and in particular pointers and polymorphism. If, on theother hand, you are falling behind this schedule, get as much help as you can from thedemonstrators.

Introduction (Section 3): should take you the morning and some of Monday afternoon

Classes, etc and Program development (Sections 4 and 5): this should be underwayduring Monday afternoon, hopefully complete some time during, preferrably by lunch.

Inheritance (Section 6): Tuesday morning/afternoon

Graphics (Section 7): you will probably be approaching this section some time duringthe afternoon of the second day.

Mass/spring simulation (Section 8): by Wednesday morning you will probably haveeither just started this exercise or be within and hour os so of starting.

Recursion (Section 9): you will most likely be tackling this on Thursday morning, or lateWednesday.

Project (Section 10): you should be coming on to this by Thursday, most likely sometime in the afternoon. Use the remaining time to develop your code along the linessuggested in section 10. The minimum aim is to get a 3D graphical display with userinteraction via keyboard and/or mouse.

Introduction to C++ 6

3 Program Development

As already mentioned, C++ is a compiled language, i.e. the code you have written is trans-formed into an executable in several steps. First, a compiler creates a binary representationfor a specific machine type (or object file) from each source file. Second, a linker combinesall of these translation units into a single executable.

The traditional (some say archaic) way of performing these steps is to use a simple texteditor of preferred flavour to create the input source code files, and then to manually typecommands into a shell or command line interface:

CC -c source1.cc -o out1.objCC -c source2.cc -o out2.objLINK out1.obj out2.obj -o program.exe

Here the first two lines correspond to a translation of two hypothetical source files namedsource1.cc and source2.cc, and the last line combines the outputs of these steps intoa single program fittingly called program.exe. The iteration of editing, compiling, linkingand fixing errors is called a single development cycle, and can be repeated until you arehappy with the results.

As you can imagine, invoking these steps over and over to correct your own programmingmistakes is tedious, and many modern operating systems provide a integrated developmentenvironment (IDE) in which this can be done fairly painlessly. An IDE usually comprisesan editor, compiler (to translate the edited files into machine code), linker (to bundle alltranslations into an executable), and sometimes a debugger (to find your mistakes in saidexecutable).

On Windows, the standard environment is called Visual Studio and the extra ingredi-ents it provides are:

1. a dynamic debugging tool; this is a program that enables you to step through acompiled program line by line, examine the contents of variables at each stage, traperrors, and set breakpoints where continuous execution will be paused.

2. a way of organising multiple source files, known as a project in a solution, whichenables compilation, linking and generation of an executable without having to typeall the command line gibberish; one nice related feature is that compiler errors appearas clickable links which then transport you right to the offending bit of source code.Within a solution, you can have several projects which share similar code.

3. it has an online help which gives you a search function to access common functions. Youcan access this help by pressing ”F1” and search for a specific term, or by highlightingtext in your source code or error messages and then pressing ”F1”. The online helpthen searches for the highlighted text automatically.

If you start the Visual Studio for the first time, it will take some time to process someinternal data and finally ask you in which environment you want to start. As we areprogramming in C++, the C++ environment is appropriate.

The IDE then shows a list of projects which correspond to the first assignments in thiscourse, and should look similar to the screenshot in figure ??. The project you are workingon is highlighted in bold in the solution explorer. To enable a different project, highlightthis project’s name and select ”Set as StartUp project” from the ”Project” menu. Amongother things, this tells the debugger to start the program associated with the active project.

Introduction to C++ 7

Figure 1: A screenshot of the Visual Studio integrated development environment. (1) Theintegrated editor (2) The ”Project Explorer” shows all projects contained in the solution,and their accompanying files. (3) The output window for error messages.

4 A simple program

A small application to perform a dynamic simulation (a ball falling and bouncing undergravity) has been written for you and can be found in the two source files in the ballproject, ball.h and main.cc. You can view these files by clicking first on the ballproject, which shows subfolders ”Header Files” and ”Source Files”. In each of these you willfind required files which open in the editor environment if double-clicked.

The first main thing to understand is the idea of a class, which is a C++ descriptionof related data. Consider the example in ball.h:

• The class definition consists of the word class followed by the name of the class beingdefined (Ball), and then two parts, public and private.

• In this instance there is nothing in the private part.1 The public part consists of threefloats which describe the instantaneous state of the ball, and a function (a method)which will (when you have written the code) update the dynamic state of the ball forthe time-step of duration delta t.

• The class definition is enclosed within “{}” and terminated with a semicolon “;”

Note the following about the source code in main.cc

• The compiler directive #include "ball.h" causes the source code in ball.hto be directly inserted. It is standard practice to put class definitions and functionprototypes in a header file or include file (the .h file) and then to include the filewherever/whenever the definitions are needed.

• A variable g is defined to represent acceleration due to gravity. The keyword constensures that its value cannot be changed during the run-time of the program.

• A typical C++ program has a function called main which is called when the programstarts. Arguments from the operating system is passed to the program through the

1A eunuch?? ;-)

Introduction to C++ 8

variables argc and argv, making a program a black box to the operating system asa function definition is to a programmer.

• An instance of the class Ball, called b, is created by the declaration Ball b;. Notethe distinction between the class definition which just describes the data structure,and an instantiation of the class which is a variable or object defined according tothe class specification.

• The variable or object b (of type Ball) is declared “inside” the function main. Itcan be used and manipulated by code in main, but it is invisible to code outsidemain (for example in another function); its scope is local to main. If it had beendeclared outside all functions then it would be a global variable or object, visible toall functions. In general global variables should be avoided, but there are occasionswhen they are either necessary, or lead to simpler and/or more efficient solutions. Ifyou think you need to use one, it would be a good idea to ask a demonstrator if thereis not a better way of doing it.

• Note that class members (i.e. the data and methods which comprise the class) areaccessed via the “.” operator, as in (e.g.) b.pos = 10; – note that this is the samesyntax as for accessing fields in a structure in matlab

• Note the use of a for loop to get a fixed number of iterations. Again, this is similarto matlab but the syntax of a C/C++ for loop is different.

• The statement

std::cout << b.pos << std::endl

deserves some further attention. The operator “<<” is how things get written tothe terminal window in C++. std::cout is known as an output stream andits definition is included by the compiler directive #include <iostream>. Thestuff to the right of the << gets written out to the screen. In this case first the currentposition of the ball is written, followed by an end-of-line character (indicated by thestd::endl).

Make sure you have a reasonable understanding of all the points above. Ask a demonstratoror look in one of the texts if you are unclear on any of these points.

Compile the program. First make sure you are compiling the right project.

• Select the ball project and set it as the StartUp project in the Project menu.(Menu → Project→ Set as StartUp Project). The name of the project should berendered bold.

• Select ”Build ball” from the ”build” menu. (Menu → Build→ Build ball).

This runs the C++ compiler and linker on your program. After a few seconds translationwill be complete and should leave you with a summary of the process in the error window:

1>ball - 0 error(s), 0 warning(s)========== Build All: 1 succeeded, 0 failed, 0 skipped ==========

Introduction to C++ 9

If you navigate into the output directory CXXCWM\build\Debug with Windows Explorer,you will see that a executable file ball.exe has been created.

Now start the executable file. This is done in the IDE by selecting ”Run without De-bugging” in the Debug menu (Menu → Debug→ Start without Debugging, or Ctrl+F5).A command line window will pop up, displaying the output of the program. If you have notmade any changes to the source files then you should get a list of 200 10s.

If you start the program, but instead of its expected output get a message box clam-ouring about a missing DLL file, then disable Incremental Linking in the project: Project→Properties→Configuration Properties→Linker→General→Enable Incremental Linking:No.

Alternatively, you can let a demonstrator help you with this. Note that this problemmight happen again in a different project.

Your task is to make this a little more useful by writing some code for the member functionUpdate by editing the file ball.h. Your code should update the position and velocity ofthe ball according to its equations of motion, and detect if/when the position becomes lessthan zero and reverse the velocity in that case.

If you are lucky your code will compile first time. More likely, however, is the eventualitythat the compiler produces one or more errors. If so, go back to the editor and try to fixthe first error that the compiler reports – this will often fix lots of subsequent ones as well.Once your program compiles without errors, run it.

If there were errors, you can fix them by clicking on each error, and the cursor will betransported to the right location in the right source file within the editor [if you didn’t getany errors, try deliberately inserting a syntax error into one of your sources to see whathappens].

The debugger component of Visual Studio is perhaps even more useful. It enables aprogrammer to step through a program as it is running, pausing, examining variable values,etc.

Try the debugger out on your executable ball:

• Place a breakpoint on the line where the Ball object gets instantiated. Similar toMatlab, you click left to the start of the line. A small red ball should appear.

• Select Menu →Debug →Start or hit F5.

• If you have changed the source, a small window will pop up, asking you whether youwant to build it. This is a good idea. Keeping this window from appearing, too, andyou can tick the little ”Do not show this dialog again box”.

• Placing the cursor over the icons either on the debugger toolbar will tell you brieflywhat each does. The most important are summarised below (see figure ??):

– Stop at: insert a breakpoint at the location of the cursor in the source code. Pro-gram execution will stop at this point giving you the chance to examine variables,etc

– Step into: execute the current line of code, but if this involves a function call,then stop at the first line of the function

– Step over: execute the current line of code then stop again

Introduction to C++ 10

Figure 2: The Debugger toolbar that only pops up when debugging is circled. (1) showsthe variables currently in scope, (2) shows the current call stack, which can be navigated bydouble clicks. (Compare to ”dbup” and ”dbdown” commands in Matlab)

– Start/Continue: Start debugging or continue execution from the current loca-tion (until another breakpoint is met)

You can halt the program mid-flow by hitting Control-Break, and this will bring youinto the debugger at the current line of execution.

Try out the various options and menus. In particular try to discover how to display thevalue of a variable (eg ball). Once you have done this, step through the program one lineat a time examining how it changes during the for loop. Also try inserting a breakpointand continuing execution to observe the program stopping at the breakpoint.

Rather than spending too much time going into all the options, it is probably better tolearn “on the job”. Next time you use the debugger, it will probably be in anger!

4.1 Redirection and Command Line Arguments

You can see if the results of running the program are sensible more easily by viewing theoutput graphically. Similar to the input arguments of a program which come from thesystem, you can also tell a program where to send its output to. Intead of displayingthe textual output, you can redirect it to a file. To do so, open the project properties(Menu →Project →Properties (or Alt+F7)) and navigate to the Configuration Properties,Debugging submenu. Simply specify the redirection and desired filename in the ”Commandarguments” text field, see figure ??., e.g. "> H:\out.txt".

Start Matlab and plot the output:

>> cd H:\>> load out.txt>> plot(out)

Does it do what you expect it to? Does the ball gain or lose height? Does the ball gainor lose energy (you could write a method called energy which computes the instantaneousenergy and write this out at each iteration:

std::cout << "Energy = " << b.Energy() << std::endl;

Introduction to C++ 11

Figure 3: Slightly hidden, but there: The command line and redirection options. Observethe > symbol.

4.2 Encapsulation

On to the next project. Select the ball2 project and enable it (Menu →Project →Set asStartUp Project).

View the code in ball2.h and main2.cc. It does exactly the same as the previousprogram and so is naturally quite similar, but there are some important differences in theclass definition ball2.h and the variable declaration in main2.cc.

• A ball’s state information is now stored as private data. This means that only theclass’ member functions have direct access to the data

• The position is now accessed via a method (this type of simple method is commonlyreferred to as an accessor). The const after the function header indicates that thisfunction doesn’t change any of the object data.

• Whenever a variable is declared in either C or C++ the runtime system allocatesspace for the variable. In C++ the programmer optionally has the opportunity todo some extra things; often this will include initialising the variable to some sensibledefault value. This “extra” work is done by a constructor, a special method with noreturn type and which bears the name of the class. The constructor here accepts 3parameters which define the initial values of position, velocity and acceleration (Makesure you understand this! Ask a demonstrator if you are confused).

The new Ball class has the virtue that it is impossible from outside the class to changethe internal state; the internal state of a ball is effectively “write-protected” from the restof the program. The class Ball therefore now encapsulates the required functionality. To-gether, the constructor, the accessor and the update function provide an external interfaceto a private internal representation.

Fix version 2 of the ball program so that the update function works as in version 1. Compileand run it (if necessary entering into the edit-compile-run development cycle to fix anylingering problems).

Introduction to C++ 12

You can make the program more flexible by prompting the user to enter the initial heightof the ball. Let us create version 3 of the program to accept some user input. First copyversion two of the .cc file to main3.cc. The simplest way is to open main2.cc in theeditor, then select ”Save As...” from the ”File” menu. Place it in the ”src/intro” directorynext to the other source files you have worked with so far.

Now add this file to the ball2 project. From the ”Project” menu, select ”Add Ex-isting Item...”, navigate to CXXCWM\src \intro, select main3.cc. Finally, remove themain2.cc file from the project: Right-click the file, select ”Remove”.

Insert the following code at the start of main (i.e. just before the existing declarationBall b(10,0,g);)

float height;std::cerr << "Enter initial height: ";std::cin >> height;

and change the declaration to

Ball b(height, 0, g);

Notes:

• The output stream std::cerr is similar to std::cout, so the second line of thiscode just writes some text to the terminal. 2

• the input stream std::cin is attached by default to the keyboard. Thus the state-ment above takes the user input from the keyboard and stores the resulting numberin the variable height.

• Unlike C which insists on variables being declared only at the start of a block ofcode, C++ is less fussy. Thus the declaration of b can occur after the opening fewstatements (but it must still appear before it is used).

2the difference between cout and cerr is that the former is buffered meaning that data written to itare not guranteed to appear instantly. cerr is not buffered

Introduction to C++ 13

5 A more complicated program

We could extend the simple program above to something more general by adding extrafloat variables to represent the x and z components of position, velocity and acceleration,and changing the definition of Update, etc.

A cleaner way of doing this is to create a data type to represent a vector in 3-space. Tothat end we shall create a data class called Vec3 and define some associated functionality.

5.1 A program module and library

Change to the project ”libvec” (Select, then Menu →Project →Set as StartUp project).You will find the shell of a mathematical vector class has been written for you in vec3.h.This header file contains the class definition, showing the data and methods, includingconstructors and accessors, and also the function prototypes of several vector operations.

• The compiler directive #ifndef Vec3 checks to see if the symbol Vec3 has pre-viously been defined. If not then all the code up to the corresponding #endif isincluded, otherwise the code assumes the code fragment has already been seen. No-tice that the first bit of code after the #ifndef then explicitly defines the symbol(viz, #define Vec3 ). This is a sneaky (but very standard) way of ensuring that thecontents of each include file are only ever included once.

• Three different constructors are provided:

1. a “default” constructor which sets the coordinates of a new Vec3 object to zero;

2. a constructor which takes three coordinates (c.f. the Ball example).

3. a copy constructor which takes an existing instance of a Vec3 and creates anew one with identical coordinates

Here we have three functions with the same name, but performing apparently differentoperations. How does the compiler know which one to call? It does it by matching thetypes of parameters in the function call, to those in the declaration. If it finds a matchit uses the matching version. Only if none of the versions matches does it report anerror.

This is an example of a more general concept called function overloading which canapply to any function or method in a C++ program. In effect, the C++ compilergives each function a unique name comprising its name (as specified by us) and thetypes of its formal parameters.

• The “&” in the parameter declaration

Vec3(const Vec3 &v)

means that the object v (of type const Vec3) is passed by reference not byvalue. This idea warrants further explanation.

The default in C and C++ for atomic data types (such as int, float, etc) and forsimple compound data structures is to pass by value. This means that at the timeof calling the value of the actual parameter is copied onto the stack and behaves

Introduction to C++ 14

just like a local variable in the called function. Modifications to the parameter withinthe function affect the stack copy and not the actual parameter.

The alternative indicated to the C++ compiler by the “&” is to put a reference, orpointer to the object on the stack. This has two important consequences and associateduses:

1. For large objects the cost in time and memory of making copies can becomeoverwhelming. It is simpler and cheaper just to pass around a reference to amemory location

2. Changes made to reference parameters have effect outside the function, thus a callto swap(x,y) using the code on the right will have the desired effect of swappingthe values of x and y, but the one on the left will effectively do nothing:

void swap(int a, int b) { void swap(int &a, int &b) {int tmp=a; int tmp=a;a=b; b=tmp; a=b; b=tmp;

} }

A call to the procedure on the left using swap(x,y) will copy x’s value into aand y’s value into b. a and b are then swapped but their values disappear whenthe program leaves the function swap. The data in the memory associated withx and y is unchanged.A call to the procedure on the right results in a being associated with the memorylocation of x (likewise for y and b). So the function has the desired effect.

To distinguish these two very different uses of pass by reference, it is good practiceto use the const keyword to indicate that efficiency is the sole reason for pass byreference and the parameter value will not change.

Thus in C++ we have the following ways of passing parameters:

– void func(int x) pass-by-value, x is a variable/object whose scope is thefunction func, so it is just like a local variable. Its value can change withinfunc but this will have no effect on the value of the actual parameter.

– void func(int &x) pass-by-reference, x is a reference to the actual parame-ter. Changes to x are equivalent to changes to the actual parameter.

– void func(const int &x) pass-by-reference, x is a reference to the actualparameter but changes to x are not permitted

Note also that the default mechanism for passing arrays in both C and C++ is byreference (so no need for the & if the parameter is an array).

The implementation of the methods and functions is in vec3.cc. Note the following:

• For small functions it makes sense to put their implementations inside the class defi-nition in the .h header file. However for larger functions and classes this can rapidlyresult in large, cluttered and hard-to-read header files. Instead it is good practice torestrict the class definition in the header to function prototypes and to implement thefunctions in another file. The standard practice is to have a .cc file of the same name.Thus in our case, vec3.h and vec3.cc define the class Vec3. Such an encapsulationof functionality is also called module.

Introduction to C++ 15

• When the code associated with a method is declared outside the class definition likethis, it must be preceded by the class name and scoping operator “::”. Thus wehave the function header

double Vec3::Mag()

to indicate that this is the implementation of the Mag method in the class Vec3.

• In C and C++ operators such as +, *, etc are just functions with special syntax,so that we can conveniently write a + b instead of add(a,b). However since theyare are just functions and can be overloaded just like any other function. In C, forexample, the division operator / behaves differently for different argument types

The way to overload operators in C++ is to create a function with the special nameoperatorXX where XX is the symbol associated with the operator. There are severalexamples in the file vec3.cc (and vec3.h).

Thus we define vector addition, subtraction, and then can conveniently write, e.g.,a+b for the sum of two vectors, or 2.0*a for the vector twice as long as a.

• The operator “<<” (and similarly “>>”) for input (output) can be overloaded like anyother operator. In this case << is overloaded to define a standard way of writing avector to the terminal.

The complete set of functions and operators has not been implemented correctly – thatis up to you. Nevertheless the code in the module should compile without error and cannow be used within the context of a more complicated program.

5.2 Libraries

Compiling a module like this in isolation from the rest of a program results in an object filevec3.obj which contains a compiled version of the Vec3 class and its function/operatorcode. It does not constitute an executable in itself, as it lacks for example the operatingsystem’s entry point (remember it does not have a main function). A collection of thesefiles is called a library, which other programs can reuse in different ways.

You can thus compile and link this project, but not run it without an appropriate exe-cutable.

5.3 Testing the library

Before moving on to an actual use of the Vec3 module, it would be a good idea to test thecode by linking it with some simple test routines. A simple program to test the functionalityhas been written for you and stored in vectst.cc, as part of the project ”vectst”. Switch tothis project (Menu →Project →Set as StartUp Project), it should compile and link withouterror.

Note that vectst.cc uses functions from the Vec3 module, but the actual Vec3 codeis not part of this test project. The reason for this is the dependency of the vectst projecton the library libvec.

Running the program (Menu→Debug→Start without Debugging) should produce someoutput, but which has some errors.

Introduction to C++ 16

Consider the difference between 25/10, 25.0/10.0 and 25/10.0. Check with a demonstratorthat you understand the differences. Think of a very simple C++ test (e.g. a single line)to confirm your theory and add it to the vectst.cc program.

Fix the function implementations in the file vec3.cc and recompile and link so that theprogram vectst.cc gives the correct results.

5.4 Combining modules

We are now going to create a new project which will be added to the existing developmentenvironment. This option leaves you with access to the files you already created, automati-cally incorporates changes into previous projects, and simplifies use of the existing code inthe libvec library.

5.4.1 Setting up a subproject

These insturctions will guide you through the process of setting up a project. A demonstratorwill be more than happy to assist you here if you encounter problems.

First, create a new, empty subproject: File →Add →New Project...Don’t let the following dialog (see figure ??) dazzle you with its options. You want a

simple application, which is created as follows:

1. Select ”Win32” as Project Type,

2. and ”Win32 Console Application” as subtype.

3. In ”Project Name” type ballvec,

4. and in location type ”CXXCWM\build”.

5. Click the ”OK” button, which will take you to another, smaller dialog.

6. Click ”Next” on the first page, and make sure ”Console Application” and ”Emptyproject” are enabled.

7. Click ”Finish”.

You are now back in the solution explorer, and should be left with a new project ballvec.Right-click this project, select ”Set as Startup project”. The project’s name should bedisplayed bold.

We are now in a position to use this Vec3 class to improve our Ball class. First, copya working version of your ball source code into the ballvec directory: In WindowsExplorer, go to CXXCWM\src\intro, select ball2.h, main2.cc and copy them intoCXXCWM\src\ballvec. Rename ball2.h to ballvec.h.

Now we’ll add existing files to the project which give you a similar skeleton as in previousexercises. From the ”Project” menu, select ”Add Existing Item...”, navigate to CXXCWM\src\ballvec, select ballvec.h and main2.cc. Finally, tell the linker that it should use thelibvec library in this project. Click Menu →Project →Dependencies and select ballvecas dependant, and libvec as dependency (see figure ??).

Introduction to C++ 17

Figure 4: Options for the new project. Left: Project type (1) and subtype (2), name (3)and location (4). Right: Click ”next”, then make sure you tick the ”empty project” box.

5.4.2 Back to the code

What will be needed for the new vectorial version of the Ball class?

1. a new line at the start of ballvec.h which includes the file vec3.h

2. remember that the include file is now called ballvec.h so change the appropriateinclude line in main2.cc

3. the type of the private data elements in the Ball class will need to be changed fromfloat to Vec3, as will the arguments to the second constructor

4. the methods GetPos and Update will need to be changed in line with the new internalrepresentation

Of course if you get stuck making these changes, please ask a demonstrator for help.

Figure 5: Add libvec as a dependency to ballvec.

Introduction to C++ 18

Compile the new ball version and test the results. If you write the position results asthree floats per line you can then load all the data into matlab (see section ?? how to redirectthe output):

>> load out.txt>> plot3(out(:,1), out(:,2), out(:,3))

6 Inheritance

C++ enables the programmer to create hierarchies of classes using a mechanism known asinheritance. A so-called derived class is one which inherits all the data and methods ofthe parent class, but can add extra data, functionality (or overload the parent’s functionsto do something different and/or more specialised).

The standard example of a class hierarchy given in texts is usually one that has little to dowith computers (e.g. fruit or animals; viz the “class” of animals has certain properties, whilethe derived, or specialised versions dog, horse and bird have the same set of base properties,plus some others). Some more concrete examples, such as a hierarchy of application windows,together with diagrams showing the class hierarchy, are given in the lecture notes thataccompany these course notes.

The power of inheritance is rooted in the fact that a function that makes use of onlybase class properties and methods, can accept as an argument (i.e. a parameter) an instanceof any derived class. Furthermore, under certain circumstances (which we won’t go into)at run-time the program can “work out” the derived type and can call the appropriateoverloaded methods instead of the base class ones. For example, a window manager programmight store a list of windows. To redraw all of the windows it would iterate through itslist calling a redraw method for each window. Though the windows may all be different(GraphicsWindow, TextWindow, etc) the correct redraw method will be called.

OK, so maybe you can’t get your head around this. Never mind for now! Let’s developa simple class hierarchy that lies somewhere in between the fruit and windows exampleson the scale of “contrivedness”. Suppose, we wanted add to our dynamic simulation someother shapes, that perhaps even had some other properties (e.g. angular velocity). We couldjust write new classes in exactly the way that we did with the Ball class. What we wouldprobaby find is that the classes shared some common data and methods, and so we couldconsider organising the classes in to a hierarchy.

Have a look in the project inherit. You will find a file dynamicobj.h that definesthe base class, and two other files dynamicball.h and dynamiccube.h that definederived classes.

Notes:

• Inheritance is indicated by the first line of the class:

class DynamicBall : public DynamicObj {

Read the colon as “inherits from” or “is derived from”.

• Note that the ball state does not appear anywhere in DynamicBall; it does not needto it is inherited from DynamicObj

Introduction to C++ 19

• The constructor contains some unfamiliar syntax. The body of the constructor is justthe {}, so it does nothing. However the part after the colon means that to create aDynamicBall the program first needs to create a DynamicObj. [As always, ask ademonstrator if you don’t understand . . .]

• DynamicBall and DynamicCube share roughly the same abstract definition hencewe have created DynamicObj that defines the core functionality.

• The DynamicBall class overloads the definition of member function Update. Aninstance in the code of ball.Update will call this function. However DynamicCubedoes not define Update, instead relying on the version defined in the base class; i.e.a call to cube.Update will invoke the base class version of Update.

• In the class definition for DynamicObj rather than the familiar keyword private,we now use protected. The difference is that protected data are private to theclass and all its derived classes, while private date are strictly private and cannot beaccessed by derived classes.

Time to try these ideas out... Complete the exercises below:

• Create a new derived class DynamicCuboid with private data members specifying its3 dimensions,and place it in a file H:\CXXCWM\src\inherit\dynamiccuboid.h,which you then add to the project.

• You can use the functionality in Project →Add New Item... (see figure ??) to createand add the files. You can also simply copy an existing file, add this to the projectand change the contents appropriately.

• Sketch a diagram of the class hierarchy and check it with a demonstrator.

• Create a new class World in a file H:\CXXCWMsrc\inherit\world.h that containsone public instance of each derived class, and has its own Update function thatcalls each of the update functions of its members in turn. You will need to create aconstructor for World that initialises the positions, velocities and accelerations of thethree dynamic objects.

• Compile the application and run it. Note that you will either need to call the Worlddata members ball, cube and cuboid, or change main.cc to use the names youhave chosen.

• Check that it does what you expect. Launch the debugger and set breakpoints in thebase class update function and in the derived ball class update function to confirmthat the right function is being called at the right time.

• Add an Update function to cuboid that causes it to bounce like the ball, but thatcauses the height to be reduced (by say 20%) on impact. Again test this in thedebugger to be sure the right methods are being called.

More notes:

Introduction to C++ 20

Figure 6: Add new header file: Select the right type (.h), name and the right location.

• Make sure you understand the difference between a class containing a data type andone that inherits from a data type. Occasionally they can be used to accomplish thesame thing, but are semantically different: the distinction is that a class which inheritshas an “is-a” relationship with the parent class (i.e. derived class is an instance of theparent, albeit specialised) contrasted with the “contains” relation in the other case.You should use this as a rule of thumb for deciding which to use.

• Your World class should not inherit from DynamicObj even though it has an Updatefunction, since the world is not a dynamic object. Though if we were modelling asystem with lots of different moving frames of reference (eg the Solar System) thenperhaps it would be... (but it would still contain the other dynamic objects.

• C++ derives much of its power through the inheritance mechanism. In the nextsection. for example, we use inheritance to define “graphically capable” instancesof our dynamic objects. As aluded to earlier, some of these ideas are beyond thescope of the current course, but do optionally ask a demonstrator about run-time typeidentification if you are curious.

7 Graphics

The dynamic simulation you have created would be much more interesting if it could begraphically viewed in “real-time” rather than as a static plot. We shall use the inheritancemechanism described above to achieve this.

A graphics library has been provided for you on the system. It is based on the OpenGL3D graphics standard, and enables you to draw rectangles, blocks, spheres and cylinders,to colour and/or texture map the objects, and to manipulate the viewing location. Anonline manual explains the relevant functions and classes. You can view the manual in aweb-browser by going to

U:\C++ cwm\doc\index.html

In particular, from here, follow links to “File list” and then “gldraw.h” to get a list ofavailable drawing functions and a brief description of each.

Most of the relevant bits are also reproduced in the Appendix of this document.The task is to create a class GBall (say) which is exactly like a ball, but which also is

able to draw itself in a window. Thus GBall will inherit from DynamicBall.

Introduction to C++ 21

Such a definition has been created for you in a file called gball.h which you will findby changing directory to src\gball (using Windows Explorer). Look at the definition ofGBall in gball.h and note the following.

GBall inherits from both DynamicBall and GraphicsObject. We know all aboutthe former, but what about the latter? Here is a brief (and probably incomprehensible)explanation (a demonstrator would be delighted to give a more detailed one if you arecurious)

The “base” class GraphicsObject has been defined as part of the graphics library. Infact the class has no data, simply a function called Draw. Unlike our DynamicObj class thatprovided a “default” Update function, GraphicsObject does not give an implementationfor Draw. This forces the programmer (i.e. you) to write a Draw function for every classthat inherits from GraphicsObject. The function you write must conform to the baseclass’ prototype (i.e. have the same name, return type and parameter list).

The graphics library defines a GLDisplay class that brings up a window, and knowsabout GraphicsObjects. When the display is drawn, it simply calls the Draw functionof every GraphicsObject instance that it knows about. How does it know about them?You need to tell it using the AddObject method of the GLDispay class.

To summarise, then: GBall is just a DynamicBall but with the additional feature ofbeing able to draw itself, using a function called Draw. The detail of this needs to be filledin by you – check the graphics library manual online for functions which are likely to beuseful . . .. Since it will probably be a fairly simple function, filling it in within the headerfile is ok – but remember for larger function implementations it is probably better to havejust a prototype in the header file and the full source code for the function in a .cc file (butproperly scoped as in the Vec3::Mag example).

Following the list of sub-tasks below should get to the point where you have a workingprogram:

1. Create a new project, called gball, as outlined in section ??. Choose H:\CXXCWM\buildas location.

2. Make the gball project dependent on the libvec library.

3. Add the working version of your DynamicBall class definition (i.e. the dynamicball.hand dynamicobj.h header files to the gball project (Menu →Project →Add Exist-ing Items...). These files do not need changing at all, and we can proceed to create thenew graphical version GBall which inherits from Ball with some ease and elegance.

4. Most of the code for GBall has been written for you already and as you have seenit is in gball.h. Add this and the main.cc file in H:\CXXCWM\src\gball to theproject.

5. You will need to create a window in which to do the graphics. The functionality fordoing this is available in the library provided for you, and some example code thatcalls the relevant library functions is given below in main.cc.

The creation of the window is achieved by creating a variable (or in “object-orientedspeak”, instantiating an object) of type GLDisplay (see below).

Introduction to C++ 22

int main(int argc, char *argv[]){

GLInit(argc, argv); // Opens GL

GLDisplay disp(500,500); // create a 500x500 window called dispdisp.AddObject(ball); // add ball to the list of graphics objects

// set viewing pos to 0 1 -5 looking at 0 0 0disp.SetViewPoint(0,1,-5,0,0,0);

GLLoop(myfunc); // infinite loop}

This code initialises OpenGL, creates and initialises a window and sets a viewpoint forthe 3D graphics to be drawn in the window, and then enters an infinite loop in whichit repeatedly calls the function myfunc.

6. For this to work, of course, your program needs to implement the function myfunc sothat the ball state has a chance to be updated. myfunc is defined in main.cc also,and looks something like:

void myfunc(double t){

// update ball positionball.Update(0.05);// indicate that the graphics need to be redrawnGLDisplayHasChanged();

}

Note that the argument t is the (real) time in seconds since the last time myfuncwas called. So, once you have the code working, try changing the code to readball.Update(t) instead of ball.Update(0.05).

7. Finally to tell the IDE that you want to link against the graphics library. This can bedone conveniently as follows:

• Set the gball project as StartUp project.

• switch to the ”Property Manager” view, right click the project and select ”AddExisting Property Sheet...”. Navigate to H:\CXXCWM\build and select the filelab default.vsprops. (See figure ?? for details).

• Switch back to the Solution View.

• In the project properties, navigate to ”Configuration Properties →Debugging”and specify H:\CXXCWM\build as ”Working directory”. In this directory isa depending library, glut32.dll, which needs to be on path or in the samedirectory as the executable.

Introduction to C++ 23

Figure 7: Add graphics-specific settings to a project in the Property Manager.

Build this, iron out the compilation errors, and run it. Carry on with the edit-compile-run-debug development cycle until you have something that works the way you expect itto.

Here are some additions to make to your working program:

1. In class GBall add a data member to store the colour of the ball. The constructorwill need to take three extra arguments of type unsigned char representing thered, green and blue colour channels.

2. Add another type of dynamic object so that you have two different shapes movingaround.

3. Add some code to draw a floor for the ball to bounce on. This actually requires a bitof thought. Two alternatives (among the many possiblities) spring to my mind:

(a) Create a new class called Floor that inherits from GraphicsObject, and addan instance of it to the display using AddObject. Floor of course. does notneed to inherit from DynamicObject

(b) Create a new class called World that inherits from GraphicsObject and con-tains all the dynamic objects. The world would have an update and a drawfunction. The update function would call all of the contained dynamic object up-date functiosn in turn (and probably should even take over the task of detectingbounces). The draw function would in turn draw each of the contained objects.Note that if you do it this way, the contained objects no longer need to be addedto the display using AddObject.

Introduction to C++ 24

8 Building your own application

You have now encountered many of the major concepts in C++ program. Up to now muchof the code has been provided for you with you making minor modifications to it. It is nowtime to do some real coding on your own (ish).

Use the examples and patterns of the examples you have worked on to this point to helpyou design and code your own application.

The task is to create another slightly more complicated dynamic simulation; a mass-springsystem consisting of N masses and N+1 springs arranged in a line. You should, of course,create a new directory, say cxxcwm/spring so that you don’t clutter your other workingdirectories.

Before you start coding you should give consideration to what objects you will need(i.e. classes), what they will represent, what responsibilties they will have, and how theywill interact. You should discuss your design with a demonstrator before proceeding to theactual coding.

Some suggestions/hints:

• Design a Spring class, and a Mass class. Each will have some private data, presumablyeach will have an update function to change its current state, and each should knowhow to draw itself. Probably the Spring class will need a method Force which returnsthe current force exterted by the spring.

• The update function for a Mass will presumably take a force and a time interval as itsarguments

• Design a World class which contains an array of N Masses and N+1 Springs (as-sume that Mass i lies between Springs i and i+1). A World::Draw method wouldloop through each Spring and call its Draw method and through each Mass and callits Draw method. The World would need to be a global object, and inherit fromGraphicsObject.

• You will need to provide a function that GL will call periodically (as in myfunc inthe previous example). It will probably just call world.Update(t).

• Start with one Mass and two Springs – there is no point in overcomplicating things atthe start.

• If this is all too easy, and you are ahead of schedule create a 3D system instead of the1D one. Positions, velocities and forces will all become vector quantities. . ., and youwill need a data structure (or some means at least) to represent which springs attachto which masses. DO NOT ATTEMPT THIS UNTIL YOU HAVE A 1D VERSIONWORKING AND SHOWN TO A DEMONSTRATOR. Why not? If you design yourclasses well, the changes required will be minimal once you have the simpler versionworking. However going for the complex version right from the start will definitely beharder to debug, and will almost certainly take much longer in the end.

Introduction to C++ 25

9 Recursion

As you should know, one function can call another. Can a function call itself? And if so,why on earth might we want to code such a strange thing?

The answer is yes, a function can call itself – a concept known as recursion – and thisturns out to be a very powerful programming idea.3.

9.1 Recursion as induction: a simple example

Recursion is the programming analogue of mathematical induction. A simple example mighthelp to clarify this.

The factorial function n! can be defined in terms of a recurrence relation:

n! = n× (n− 1)!, 0! = 1

This can be coded in a simple C++ function as follows:

int Factorial (int n) {if (n == 0)

return 1;else

return n * Factorial(n-1);}

Try this function out by creating a small (one module) program (in a new directory!) whichprompts the user for an integer, then prints the result to the screen. Use the debugger totrace through the program (set a breakpoint on the first line of Factorial for example),and monitor the values of n as you go.

9.2 A more complicated example

We are now going to think about a more advanced problem which can be eleganty solvedvia a recursive algorithm, namely creating a maze, such as the one below:

3ECS students will no doubt have done so much recursion as to have it oozing from all orifices

Introduction to C++ 26

---------------------------- -| | | || --- ------ ---| | | | | | || --- ------ ---| | | | | || --------- ---------| | | | | || --- ------ ---------| | | | || --------- ---| | | | | ||------ --------- --- ---| | | | || ------ --- --- ---| | | | | || --------- ---| | | | ||------------------------| | |- ----------------------------

Below is a description of an algorithm to compute a maze.4 We assume that a mazeconsists of two dimensional array of “cells” and that our initial maze has all the wallsbetween cells intact. The function is then entered for the first time with the current cell setto be the starting point of the maze:

Mark the current cell as visited

LOOP: as long as the current cell has unvisited neighbours,

1. choose one of the unvisited neighbours at random

2. “knock down” the wall between the current and the chosen cells

3. recursively call this function with the chosen cell as the current cell

In order to implement this algorithm you should first think about your representations.Some hints/suggestions (not exhaustive) are given below:

• You will need to design a Maze class. Give thought to what data it will need to storeand what methods it will have. Minimally it will need a two dimensional array of cells,and a method (recursive) to compute the maze

• You will probably want/need to overload operator<< so you can conveniently writea maze to the screen

• You will need to design a Cell class which will minimally contain information aboutwhich walls are intact or broken, and whether it has been visited or not

Discuss your representation ideas with a demonstrator before proceeding to code them,and then create a new directory/project in which to develop your program.

4Note that better algorithms exist, but this one is quite straightforward

Introduction to C++ 27

A good idea would be to code the classes but to leave the compute method which is tem-porarily empty. You can test that your class definitions compile and that the operator<<and constructors work by printing out the default start which is just a grid of unconnected(block-off) cells.

Now code the recursive compute method. You will need to be able to generate a randomnumber. The system function rand() generates a random number (of type int) between0 and the system constant RAND MAX. Function and constant are defined in the header¡cstdlib¿. You can get more information from the manual/help page by typing rand(),highlighting it and invoking the online help with F1. To convert such a number into aninteger between 0 and N-1, use the expression (for example5):

int choice = static_cast<int>(floor(1.0*N*rand()/(RAND_MAX+1)));

Here static cast<int>(...) is a special type-conversion operator. In this case is takesa double and converts it to and int. Look for floor in the reference to find out whatthat function does.

Since rand() will always generate the same “random” sequence each time your programruns, you may want to “seed” the random number generator. One way of doing this thatgives a degree of randomness is to use part of the current time as a seed. To achieve this,here is some code:

#include <ctime>...{

clock_t t;t = clock();srand(static\_cast<unsigned int>(t));

}

To get this to compile you will also need the line #include <ctime> at the top of themodule. See the man-page for srand() and clock() for details.

Design your classes, code them up, compile, debug, etc until you have a working mazeprogram.

10 Project

Over the remainder of the course, your aim is to use your maze program as the basis fora 3D, interactive computer game, in which the player must navigate through the labyrinthwith a “mouse’s” eye-view (see, for example a screen-shot from an implementation of theseideas below). As usual, start a new directory and copy the files you need from your simplemaze program.

5this is actually not advisable, as the random numbers will be biased. In this course we’ll still be happywith it.

Introduction to C++ 28

A good starting point would be to use your operator<< method as a template for howa Draw method would be coded. By setting the viewpoint appropriately you could then geta top down view of the maze similar to the screen representation, but with nicer graphics.

Beyond this basic specification you have pretty much complete freedom to do as youwish. Some suggestions are given below.

One topic we have not covered yet is the idea of your program getting real-time userinteraction. The drudgery of this has been implemented in the graphics library for you.Your handle on this is (as for graphics windows) via the GraphicsObject class.

In fact, each GraphicsObject has four functions in addition to its Draw function:

KeyPressMouseClickMouseDragMouseDragFinished

Unlike Draw these functions provide a default implementation (they are not pure virtualfunctions that do nothing).

In order to get your program to react to a user event, you need to overload one (or all)of these functions in your GraphicsObject. For example, if you have a class Personarepresenting the current position and viewing direction, you could overload KeyPress likethis:

void Persona::KeyPress(int x, int y, unsigned char key){

switch (key) {case ’l’:case ’L’:

dirn -= 5.0;break;

case ’r’:case ’R’:

dirn += 5.0;break;

}

Introduction to C++ 29

return;}

which might change the viewing direction 5 degrees.If World is your sole GraphicsObject then it will instead be the world’s events func-

tions you overload.Note that although functions are provided in the graphics library to translate the viewing

poistion and rotate it, the latter operates around the origin, which is not necessarily thecurrent viewing position, and consequently its use can result in conterintuitive behaviour.A better way would be to have your Persona class store its own current position and view-ing angle, and to set these graphically using SetViewPoint, which takes size argumentsspecifying 3D viewing location, and a 3D position to look at.

Suggestions:

• Texture-map the walls using some interesting image you have (or obtain from the web)

• Colour the floor of cells which have been visited different from univisted ones

• Enable your persona to jump up to get a temporary overview of the maze

• Provide a second viewpoint

• Use gettimeofday to time how long it takes to traverse the maze

• Have some “special” cells which must be visited or avoided

• Put some moving objects (benign or nasty) into the maze

• Pretty much anything else you can think of to liven it up – but check your ideas witha demonstrator before trying to implement them.

Introduction to C++ 30

A gldraw.h File Reference

Functions for drawing things on the currently active display.

Functions

• void ClearDisplay (unsigned char red, unsigned char green, unsigned char blue)Clear the display.

• void SetPenColour (unsigned char red, unsigned char green, unsigned char blue)Set the drawing colour.

• void TranslateViewPoint (double delx, double dely, double delz)Translate the viewing position from the current location by an amount given by delx, delyand delz.

• void RotateViewPoint (double angle, double axis x, double axis y, double axis z)Rotate the viewing direction from the current by an amount given by angle (DEGREES)about the given axis.

• void DrawLine (float x0, float y0, float z0, float x1, float y1, float z1)Draw a line from (x0,y0,z0) to (x1,y1,z1).

• void DrawRectangle (float x0, float y0, float z0, float width, float height, floatangle=0, float axis x=0, float axis y=0, float axis z=1, int texture=0)

Draw a rectangle with bottom-left corner at (x0,y0,z0) and of size(width,height) at orien-tationn given by ’angle’ degrees around the axis (axis x,axis y,axis z).

• void DrawBlock (float x0, float y0, float z0, float width, float height, float depth, floatangle=0, float axis x=0, float axis y=0, float axis z=1, unsigned int texture=0)

Draw a block with one corner at (x0,y0,z0).

• void DrawSphere (float x0, float y0, float z0, float radius, float angle=0, float axis -x=0, float axis y=0, float axis z=1, unsigned int texture=0)

Draw a sphere with centre at (x0,y0,z0).

• void DrawHelix (float x0, float y0, float z0, float length, float inner radius, floatouter radius, unsigned int number of revolutions=5, float angle=0, float axis x=0,float axis y=0, float axis z=1, unsigned int texture=0)

Draw a helix with its base at (x0,y0,z0).

• void DrawHelix2 (float x0, float y0, float z0, float x1, float y1, float z1, float in-ner radius, float outer radius, unsigned int number of revolutions, unsigned int tex-ture=0)

Introduction to C++ 31

Draw a helix with ends at (x0,y0,z0) and (x1,y1,z1).

• void DrawCylinder (float x0, float y0, float z0, float baseRadius, float topRadius,float height, float angle=0, float axis x=0, float axis y=0, float axis z=1, int tex-ture=0)

Draw a tapered cylinder with its base at (x0,y0,z0).

• void Draw2DText (float x, float y, const std::string &text)Draw some text at (x,y).

A.1 Detailed Description

Functions for drawing things on the currently active display.

Author: bjt, idr

Date: 12/03/2002 These functions draw various geometric primitives on the currentlyactive display, and should only be used within the Draw() function of a Graphics-Object (p. ??) or the Redraw() function of a GLDisplay (p. ??).

A.2 Function Documentation

A.2.1 void ClearDisplay (unsigned char red, unsigned char green, unsignedchar blue)

Clear the display.

Values from 0 to 255 cover the full range for each of red, green and blue.

A.2.2 void Draw2DText (float x, float y, const std::string & text)

Draw some text at (x,y).

As the text is drawn directly onto the window, there is no 3D component.

A.2.3 void DrawBlock (float x0, float y0, float z0, float width, float height,float depth, float angle = 0, float axis x = 0, float axis y = 0, floataxis z = 1, unsigned int texture = 0)

Draw a block with one corner at (x0,y0,z0).

The size of the block is given in x,y,z as (width,height,depth), and the block is rotated by’angle’ DEGREES around the axis specified by (axis x,axis y,axis z). If a texture numberis specified then a texture is mapped onto the block, otherwise it is drawn using the currentpen colour.

Introduction to C++ 32

A.2.4 void DrawCylinder (float x0, float y0, float z0, float baseRadius, floattopRadius, float height, float angle = 0, float axis x = 0, float axis y =0, float axis z = 1, int texture = 0)

Draw a tapered cylinder with its base at (x0,y0,z0).

The cylinder can have varying radius from base to top..

A.2.5 void DrawHelix (float x0, float y0, float z0, float length, floatinner radius, float outer radius, unsigned int number of revolutions =5, float angle = 0, float axis x = 0, float axis y = 0, float axis z = 1,unsigned int texture = 0)

Draw a helix with its base at (x0,y0,z0).

The helix is made up of many circular rings, comprising ’number of revolutions’ turns overthe whole length. Texture isn’t very useful for this object. As specifying an angle and axiscan be tricky, see the alternate form below.

A.2.6 void DrawHelix2 (float x0, float y0, float z0, float x1, floaty1, float z1, float inner radius, float outer radius, unsigned intnumber of revolutions, unsigned int texture = 0)

Draw a helix with ends at (x0,y0,z0) and (x1,y1,z1).

The helix is made up of many circular rings, comprising ’number of revolutions’ turns overthe whole length. Texture isn’t very useful for this object. This alternate form of thefunction is sometimes easier to specify.

A.2.7 void DrawSphere (float x0, float y0, float z0, float radius, float angle= 0, float axis x = 0, float axis y = 0, float axis z = 1, unsigned inttexture = 0)

Draw a sphere with centre at (x0,y0,z0).

The sphere radius is specified, and the rotation only makes a difference if a texture is applied..

A.2.8 void SetPenColour (unsigned char red, unsigned char green, unsignedchar blue)

Set the drawing colour.

Values from 0 to 255 cover the full range for each of red, green and blue.

Introduction to C++ 33

B glbasicfunctions.h File Reference

Basic wrappers for GL to allow ’object oriented’ displays.

Functions

• void GLInit (int argc, char ∗∗argv)Initialise a few GL and GLUT things.

• void GLInit ()Initialise a few GL and GLUT things.

• void GLLoop (void(∗updatefunc)(double))Start the main GLUT loop using ’updatefunc’ for the idle callback.

• void GLDisplayHasChanged ()Notify GLUT that one or more displays need updating.

B.1 Detailed Description

Basic wrappers for GL to allow ’object oriented’ displays.

These functions provide a system for passing signals from the all-global GLUT functionsonto the relevant C++ displays. As a user you should only ever need to call GLInit()(p. ??) and GLLoop() (p. ??), which initialise OpenGL (ie GLUT) and start the event looprespectively. Also, you should call GLDisplayHasChanged() (p. ??) if/when one or moredisplays needs redrawing (such as when an object has been moved or changed).

The other functions should be treated as internal, and never called explicitly since this canlead to crashes if no display is active.

B.2 Function Documentation

B.2.1 void GLDisplayHasChanged ()

Notify GLUT that one or more displays need updating.

This causes (at some unspecified future time) the GLRedraw() function to be called.

B.2.2 void GLInit ()

Initialise a few GL and GLUT things.

This version assumes no command line options.

Introduction to C++ 34

B.2.3 void GLInit (int argc, char ∗∗ argv)

Initialise a few GL and GLUT things.

The params argc and argv should be passed directly from the command line, or if using theold style ”void main()” use the alternative form that takes no arguments.

B.2.4 void GLLoop (void(∗ updatefunc)(double))

Start the main GLUT loop using ’updatefunc’ for the idle callback.

This enters a loop where GLUT tracks all X events over a window and calls the abovefunctions. These then pass the signals onto the individual displays for handling. The doublethat is passed to the user update function contains the time since the last update.

Introduction to C++ 35

C GraphicsObject Class Reference

Abstract base class for objects that can be drawn by displays.

Public Methods

• virtual void Draw () const=0Redraw the object.

• virtual void MouseClick (int x, int y, int button)Mouse has been clicked.

• virtual void MouseDrag (int start x, int start y, int prev x, int prev y, int finish x,int finish y, int button)

Mouse is being dragged.

• virtual void MouseDragFinished (int start x, int start y, int finish x, int finish y,int button)

Mouse has been dragged.

• virtual void KeyPress (int x, int y, unsigned char key)A key has been pressed.

C.1 Detailed Description

Abstract base class for objects that can be drawn by displays.

This class provides no data or functionality, but guarantees that inheriting classes providea Draw() (p. ??) function. Use this class by sub-classing and filling in the Draw() (p. ??)function, eg

class MyObject : public GraphicsObject {public:

void Draw() const{DrawSphere (0,0,0,1);

}};

Optionally, classes inheriting from this class can receive keyboard and mouse events byoverloading the virtual functions KeyPress() (p. ??), etc

Introduction to C++ 36

C.2 Member Function Documentation

C.2.1 virtual void GraphicsObject::Draw () [pure virtual]

Redraw the object.

You must overload this in your subclass. When this is called, the current display will beactive, so that any OpenGL commands can be used safely.

C.2.2 virtual void GraphicsObject::KeyPress (int x, int y, unsigned char key)[virtual]

A key has been pressed.

This gives the mouse coords when the key was pressed, plus the ASCII character for the keythat was pressed (ie. you can distinguish between caps and lower case, but cannot detectshift and control keys).

C.2.3 virtual void GraphicsObject::MouseClick (int x, int y, int button)[virtual]

Mouse has been clicked.

Overload this to handle a mouse click event (note that position is in pixels.

C.2.4 virtual void GraphicsObject::MouseDrag (int start x, int start y, intprev x, int prev y, int finish x, int finish y, int button) [virtual]

Mouse is being dragged.

This is called for each movement of the mouse DURING a drag operation. If you only wantto deal with the complete drag, use the next function.

C.2.5 virtual void GraphicsObject::MouseDragFinished (int start x, intstart y, int finish x, int finish y, int button) [virtual]

Mouse has been dragged.

This is called at the end of a drag operation.

Introduction to C++ 37

D GLDisplay Class Reference

A class which opens an OpenGL window and can draw GraphicsObjects (p. ??).

Public Methods

• GLDisplay (unsigned int w, unsigned int h)Constructor.

• void GLDispInit (void)Initialise.

• void AddObject (GraphicsObject &object)Add an object to the list of things to be drawn each time.

• void RemoveObject (GraphicsObject &object)Remove an object from the list of things to be drawn each time.

• virtual void Redraw ()Redraw the display.

• virtual void MouseClick (int x, int y, int button)Mouse has been clicked.

• virtual void MouseDrag (int start x, int start y, int prev x, int prev y, int finish x,int finish y, int button)

Mouse drag event.

• virtual void MouseDragFinished (int start x, int start y, int finish x, int finish y,int button)

Mouse drag completed event.

• virtual void KeyPress (int x, int y, unsigned char key)Detect a key-press.

• void SetViewPoint (double x0, double y0, double z0, double x1, double y1, doublez1, double xup=0.0, double yup=1.0, double zup=0.0)

Change the viewing position and the target viewpoint..

• void TranslateViewPoint (double delx, double dely, double delz)Translate the viewing position from the current location by an amount given by delx, delyand delz.

• void RotateViewPoint (double angle, double axis x, double axis y, double axis z)

Introduction to C++ 38

Rotate the viewing direction from the current by an amount given by angle (DEGREES)about the given axis.

• void Clear (unsigned char red, unsigned char green, unsigned char blue)Clear the display to an rgb value (0<255).

• void DisplayHasChanged ()Mark that the display has changed and requires a redraw.

• int AddTexture (unsigned char ∗image data, unsigned int width, unsigned intheight)

Store a new texture, whose index is returned.

• int AddTexture (const char ∗filename)Store a new texture, whose index is returned.

D.1 Detailed Description

A class which opens an OpenGL window and can draw GraphicsObjects (p. ??).

This class, together with the functions in ’gldraw.h’ and ’glbasicfunctions.h’ provide anobject-orientated wrapper for some OpenGL basics. Each display knows how to draw itscontents, and handles its own mouse and keyboard events.

There are two ways to use this class. The first (simplest) method is to use the AddObject()(p. ??) function to add a series of objects to the display’s ’DrawList’. Each of these objectsis passed the redraw event and any keyboard and mouse events that arise.

The second method is to derive a subclass from this class and overload the Redraw() (p. ??)function, which draws the content (note that the DrawXXX functions are globally availableand can be called from a user class within the execution of ’Redraw() (p. ??)’). In additionyou might overload mouse and/or keyboard event functions if you wish for such things.

D.2 Constructor & Destructor Documentation

D.2.1 GLDisplay::GLDisplay (unsigned int w, unsigned int h)

Constructor.

Note that a width and height must be supplied.

D.3 Member Function Documentation

D.3.1 int GLDisplay::AddTexture (const char ∗ filename)

Store a new texture, whose index is returned.

Introduction to C++ 39

The texture is loaded from file.

D.3.2 int GLDisplay::AddTexture (unsigned char ∗ image data, unsigned intwidth, unsigned int height)

Store a new texture, whose index is returned.

These textures can then be mapped onto boxes and planes. The texture data must beformatted RGBA.

D.3.3 void GLDisplay::DisplayHasChanged ()

Mark that the display has changed and requires a redraw.

This will call your derived ’Redraw function at the next available opportunity.

D.3.4 void GLDisplay::GLDispInit (void)

Initialise.

This function should be called if the display is declared globally, but for local declarationsit should be called automatically. It won’t hurt to make a habit of always calling it.

D.3.5 void GLDisplay::KeyPress (int x, int y, unsigned char key) [virtual]

Detect a key-press.

This gives the mouse coords when the key was pressed, plus the ASCII character for the keythat was pressed (ie. you can distinguish between caps and lower case, but cannot detectshift and control keys).

D.3.6 void GLDisplay::MouseClick (int x, int y, int button) [virtual]

Mouse has been clicked.

Overload this to handle a mouse click event (note that position is in pixels.

D.3.7 void GLDisplay::MouseDrag (int start x, int start y, int prev x, intprev y, int finish x, int finish y, int button) [virtual]

Mouse drag event.

This is called for each movement of the mouse DURING a drag operation. If you only wantto deal with the complete drag, use the next function.

Introduction to C++ 40

D.3.8 void GLDisplay::MouseDragFinished (int start x, int start y, intfinish x, int finish y, int button) [virtual]

Mouse drag completed event.

This is called at the end of a drag operation.

D.3.9 void GLDisplay::Redraw () [virtual]

Redraw the display.

Overload this, but ∗DO NOT∗ call it explicitly - instead call ’GLDisplayHasChanged()(p. ??)’ which will initiate a redraw when the time is right.

D.3.10 void GLDisplay::SetViewPoint (double x0, double y0, double z0,double x1, double y1, double z1, double xup = 0.0, double yup = 1.0,double zup = 0.0)

Change the viewing position and the target viewpoint..

(x0,y0,z0) specifies the observation position, and the view is oriented to look towards point(x1,y1,z1). The up direction is given by the last three (optional) arguments.