A prerequisite for the 3-day C++ design and programming course, or for the 5-day analysis, design and programming course is that participants know some very simple basics of C++ syntax. This document covers most of what you'll probably find useful to know.
The material starts off with some Linux-based course issues. If your course is going to be a Windows-based course (which makes no difference whatsoever to the C++ itself), then you can go straight to the C++ section, after the first couple of paragraphs.
If you are used to Fortran or Algol then the first surprise when using C++ is the use of many files to hold your code. Related, commonly used definitions (and occasionally definitions--don't worry about the distinction for now) are put into "header" files. Each class is usually defined in a separate pair of files. A class' header file, with a .h filename extension, holds the definition--the data members and member function declarations--whereas the actual member function code goes in a file with typically a .C or .cpp or .cxx extension.
Compiling a large number of files would require developers to have an incredible memory and knowledge of the code structure, so a makefile is used instead. A makefile records the various dependencies that the files have on each other, and other gruesome details such as compiler switches. Writing makefiles is an arcane and unpleasant task. If you have a coding environment that does it for you (Visual C++ for example), you can be very grateful. If you can find someone who likes writing makefiles, don't have them put under medical supervision, get friendly with them and get them to write your makefiles. For the course, just hope that the lecturer brings the makefiles with them, and that they work.
All routines have a declared return even it's only "a value from the empty set void ", i.e. not really returning anything at all. (You should think of "void" in the sense of "the great void", rather than "invalid". The main() routine returns a number to the operating system, although, uniquely for main() the return statement itself is optional. With an explicit return, our main() looks like this:
Routines other than main have developer-chosen identifiers like calculateLuminosity . There are two (well three) styles for identifiers. You'll see I'm using meaningful names with capitalisation. Some use meaningful names with underscores. Some don't use meaningful names. We hope we will never have to read code written by the last group.
This routine is being declared to take two floating point number arguments (and, as we've seen, is being declared as returning a floating-point argument as well). There are several built in types including floating-point types. They are all primitive ; that is they are not object-oriented types. The built-in types are variations on bool , char , int and float . These are not very powerful, or very friendly, and we will spend most of our time implementing our own types-- classes --or getting classes from libraries. This is the object orientation. Everything is done by objects; objects are built from classes; our development work is therefore designing classes. (Additionally we have to design the type system . Demonstrating the subtle connections and differences between the class system and the type system is one of the goals of the course.)
Getting back to our routine, we next come to the code block , set between curly brackets (braces). (These curly brackets are like the begin and end of Pascal.) A code block gets executed; it's what does the work. A code block can be treated as a single statement , i.e. where the grammar says give me a statement, a code block can be given (another term for a code block is a "compound statement"). A block is also a scope region . Identifiers declared between the curly brackets of a block are only visible--in scope--there, to that code, or to any scopes nested within that scope (provided they come after the declaration). They can't be referenced from other, non-nesting, code blocks. This is to give us modular code of course; to limit the impact of changes.
The dot is the message send operator . (Technically it's called the member select operator, but if you follow the rules of righteous object-orientation, it is effectively the message send operator.) On the left is the destination object's variable and on the right is the signature of what we want it to do, i.e. we expect the object transducer to find a routine resembling voltage() in its class definition.
We give a type Measurer (a class type in this case) followed by a space and then an identifier transducer. The line is again terminated with a semi-colon. The declaration of a variable of primitive type would look like this:
All routines also have to be declared before they can be used. Apart from main , we will be being thoroughly object oriented and declaring our routines in classes. (I.e. whilst the compiler's run-time executive will run main , all application functionality will be run by objects of classes. Explaining and justifying that sentence is what much of the course is about.)
Notice that there is no then or endif or fi . And notice that we again have parentheses, but for an entirely different purpose. In fact parentheses serve many purposes: holding argument lists, holding control expressions, altering precedence in expressions, etc. (Those of you who know the language will know that the curly brackets there are not necessary if there's only one statement. However, always using curly brackets is an important safety/style guideline.)
The first part of the control is executed just once, at the outset; here, it is declaring, defining and initialising a loop counter to zero. The second part of the control is exactly like the control of a while; it is checked before each iteration, and the iteration only proceeds if it evaluates true ; here, we are using it to look for the loop termination condition. The final part is executed after each iteration; here, we use it to increment the loop counter
You have seen lots of operators already. You may have noticed that assignment is = (very common, even if mathematically suspect). The arithmetic operators and most comparison operators are pretty obvious. The non-obvious comparison operators are == for equal and != for not-equal.
Unusual to this family of languages are the compound assignment operators. They make some expressions easier to read, once you get used to them. a += b means a = a + b . Call it the add and assign operator, then you'll remember which way round it goes. There are corresponding compound operators for most binary arithmetic operators.
You can also write i++ . What's the difference? In x = y * ++i , i is incremented before it participates in the greater expression. With x = y * i++ , i is incremented after it participates. There are corresponding decrement operators -- .
This class is called CalorimeterHit. Its objects can understand the messages energy() and where(). These messages can potentially be sent from any other object. The return from the energy() message is a double precision floating point number, and the return from the where() message is a Position object. Objects of the class secretly maintain their state in some rectangular coordinate variables and an energy variable.
The actual code isn't here. This is the header . This is what you'd find in the .h file. This is what users of your class would need to include (with #include , a pre-processor directive) in their programs to properly declare your class in order that they could use it.
Notice another, and different use of curly brackets. These enclose a list; a list of class members . They, like a code block, are also a scope region-- class scope . The C++ term for the a routine in a class is a member function (the general OO term would be method); and for the variable a data member (the general OO term would be instance variable, because each instance of the class will have its own personal variable).
This looks pretty much like the routines we've already seen, other than the use of CalorimeterHit:: which is a necessary scoping statement. As the code is not in the class' curly bracket scope region, the routine has to be put specifically in the right scope.
You might be thinking, "What's the point of having a private variable e and a member function that just returns it?" Well the thing is that whilst creating software is moderately difficult, maintaining it over a long and happy lifetime is the real problem. Delegating the holding of hit energy to hit objects and hiding how they store and report it today , means that if we have a add a calibration correction tomorrow, the objects' clients will not see any change and will not themselves need to change.