Professional Documents
Culture Documents
Pai Reader CPP 2018
Pai Reader CPP 2018
Pai Reader CPP 2018
The reader here is meant as a small intro to the topics of C++ and openFrameworks we certainly
will need in the course. It is not a substitute for other sources.
For example http://www.cplusplus.com/doc/tutorial/ gives a good overview.
For openFrameworks there is on http://openframeworks.cc/learning/ a start for tutorials.
Also on youtube there are numerous videos that explain concepts nicely.
1 C++ syntax 3
1.1 comments 3
1.2 basic types 3
1.3 constants 3
1.4 variables 4
1.5 expressions 5
1.6 advanced types 5
1.6.1 enumeration types 5
1.6.2 arrays 6
1.6.3 two-dimensional arrays 6
1.6.4 struct type 7
1.8 functions 10
1.8.1 parameter list, result type and body 10
1
1.8.3 expressions and functions 12
2
1 C++ syntax
Originally, C++ is C extended by object oriented concepts. (Modern C++ is different from C with
object oriented concepts. Here, however, we choose the simple way to start, and consider that as
a stepping stone to C++ programming.)
It is recommended to have syntax references at hand, as we all have to program in different
languages all the time.
1.1 comments
include headers in your programs explaining what the code is about & name & date.
explain what variables do contain and what they are used for.
explain for fragments of code what the purpose here is, what the result.
when you use meaningful names you can reduce the amount of comment!
/* here
a
whole
block
is
a
comment
*/
For unsigned short int and signed short int, what should be the range in the table above?
1.3 constants
3
const float ThisIsAConstant = 23.0f;
const int MazeSize = 40;
Constants cannot be changed during a program execution. They are useful as global variables.
Actually, they do not increase expressiveness wrt variables, but constants allow a safer style of
writing programs.
The name convention for constants is as in the example: start with an upper case letter, start each
new word within the name with an upper case letter. (For java the name convention would be:
THIS_IS_A_CONSTANT)
1.4 variables
simple declaration
int a;
float myNumber;
multiple declaration
int a, b, c;
4
The name convention for variables is to start with a small letter. Capital letters for sub-words in the
name make names more readable.
1.5 expressions
Also expressions have a type. We also say the expression evaluates to type int or float…
int a,b;
(4*a+b)-3 is an expression
float mynumber = 3.14f;
float r = 2.0f;
(2 * r) * 3.14f is an expression
float area;
area = (2 * r) * 3.14f;
Enumeration types allow to define a set of values. This is mainly useful for writing easy-to-read
code.
In our search assignments there are the directions listed as enum type: this makes code more
readable and prevent faults introduced when coding (“east” is more intuitive than “3” for a
direction.)
enum Direction {
DirectionNorth = 0,
DirectionEast = 1,
DirectionSouth = 2,
DirectionWest = 3
};
5
1.6.2 arrays
simple declaration
int a [3][4];
or, equivalently
6
1.6.4 struct type
collect heterogeneous
aspects of one “instance”.
7
or by loops allowing to execute the same code many times.
in principle, also the structures of this section are not at all new: they are the same in Java….
1.7.1 if-then
if (boolean_expression){
// statement(s) will execute if the boolean expression is true
}
example:
if (a<=20) {
cout << “a is smaller than 20” << endl;
}
1.7.2 if-then-else
if(boolean_expression){
// statement(s) will execute if the boolean expression is
true
}
else{
// statement(s) will execute if the boolean expression is
false
}
example:
if (a<=20) {
cout << “a is smaller than 20” << endl;
}
else {
cout << “a is not smaller than 20” << endl;
}
1.7.3 switch
switch(expression){
case constant-expression :
statement(s);
break; //optional
case constant-expression :
statement(s);
8
break; //optional
an example
switch(search){
case north :
neighbour = actualCell - mazeDim;
break;
case east :
neighbour = actualCell + 1;
break;
case south :
neighbour = actualCell + mazeDim;
break;
case west :
neighbour = actualCell - 1;
// we do not need a break-statement in the last case: why?
}
or, differently
int i;
for (i=0; i<30; i=i+5) {
//do something
}
9
1.7.5 conditional loop
while (boolean_condition) {
//do something
}
example
do
{
//do something
} while (boolean_condition)
example
what is the difference between this loop and the one above?
in which cases do they give a different result?
(see tutorial questions)
1.8 functions
10
Internally, a function with a defined functionality can be implemented in different ways.
The outside determines how it can be used and called.
example 1:
example 2:
The name convention for function names and method names is to start with a lower case letter.
In one file ending with the suffix .hpp the declaration of the function is done, i.e. only result type,
name and list of parameters:
In another file, with the same name as the first, but with the suffix .cpp we have the definition of
the function, including the body:
//function definition
Direction oppositeDirection(Direction direction) {
switch (direction) {
case DirectionNorth:
return DirectionSouth;
case DirectionEast:
return DirectionWest;
case DirectionSouth: main does not need parameters,
return DirectionNorth; but has a result type int.
case DirectionWest: 0 as result indicates that the program
return DirectionEast; was successful,
}
1, or different indicates that there
12
the result of an expression can be assigned to a variable:
float area;
area = (2.0f * radius(x,y)) * 3.14f;
In Processing we have a setup part and a draw part that is executed over and over again.
This structure will re-appear in OpenFrameworks, that we will treat later.
Here, for the moment, we look at plain C++ programs.
It is better if you have first an idea what plain C++ is and how it works,
before we enter some advanced C++ based framework, offering a lot of extra possibilities.
function
#include <iostream>
definition
using namespace std;
int even_another_function(....){
....
}
function
definition
int main(){
/* the function main is the only function that
is executed automatically.
every other function to be executed has to be
called (directly or indirectly from here
*/
13
1.10 classes
An object is a group of variables, equipped with a group of operations that access these variables.
Often, we need to create many similar objects. That leads in a natural way to the concept of a
class.
A class is a "blueprint" for (similar objects. All instances of a class (objects) have the same
variables
(probably with different values) and are equipped with the same operations as defined in the
"blueprint".
In object oriented terminology, an object's variables are variously called instance variables or
member variables, and its operations are called constructors and methods.
A constructor is an operation that creates and initializes a new object of a class. In both Java and
C++, a constructor is always named after the class to which it belongs.
■ Constructors have the same name as the class.
■ Constructors do not return any values.
■ Constructors are invoked first when a class is initialized. Any initializations for the class
members, memory allocations are done at the constructor.
■
example:
// classes example
#include <iostream>
using namespace std;
// class definition
class CRectangle {
int x, y;
public:
// the constructor
CRectangle (int a,int b)
{x=a; y=b;};
// a method
int area () {return (x*y);}
};
14
This is the easiest version for a class definition: the constructor is inside. Below is another version
where within the class definition only the declaration of the constructor is located. The actual
definition (body) of the constructor is outside the declaration of the class.
(Later, in OpenFrameworks this is the way to define classes, where the declaration of a constructor
and the definition are separated as below, and even in different files.)
// output functions
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
return 0;
}
15
in an unintended way, the whole object may be messed up, i.e. inconsistent states could
be created.
■ separation of concerns: often there are different ways to realize a method, different
algorithms to implement the same thing (as you will experience in this course, hopefully).
And, first, it is not necessary to see from outside how a method or object is realized - we
are only interested how it works (disclaimers later in the course). And, second, at some later
moment, it could be the case that there is some better implementation of a method - then
we simply can replace the "internal" part of a class, and do not need to change the rest of
the program.
class Clown{
public:
float x_position;
float y_position;
float size;
private:
float x_pos_nose;
float y_pos_nose;
...
public:
// constructor
Clown(){
....
}
// methods
void draw_me(){
}
...
}
16
1.11 program structure and classes
In Processing we have a setup part and a draw part that is executed over and over again.
This structure will re-appear in OpenFrameworks, that we will treat later.
Here, for the moment, we look at plain C++ programs.
It is better if you have first an idea what plain C++ is and how it works,
before we enter some advanced C++ based framework, offering a lot of extra possibilities.
#include <iostream>
using namespace std;
int even_another_function(....){
....
}
class Defrobnicator {
.....
}
int main(){
/* the function main is the only function that
is executed automatically.
every other function to be executed has to be
called (directly or indirectly from here
*/
So far, the programming concepts are pretty much the same as we had in Processing. Even if
the syntax is sometimes slightly different.
Even if it is going into more depth, the course here will not cover all concepts of C++. In fact, it is
not necessary to know everything about C++ to write good C++ programs. Even worse, there are
a number of concepts that allow/invite to write very unclear programs. For our purposes and for
learning a clear way of thinking and programming, we aim at simple and clear structures. In the
end, complexity and unclear constructions pop up uninvitedly anyway - so the art is much more to
bring simplicity in thinking, structures and programs than to introduce spaghetti-friendly concepts.
It will certainly not demonstrate you intellectual brilliance if you write unclear programs.
17
2. compiling C++ programs
#include <iostream>
When we compile a program, first a preprocessor gets active. The preprocessor copies textually
the content of iostream into our program, resulting in an object file, that typically has the same
name as out original file, but the extension .o or .obj. Note, that iostream contains program
fragments in C++.
After preprocessing, the compilation starts. From the extended program in the object file a
program in machine language is created.
It is also typical, that we use a lot of functions from libraries. The code in the libraries is already
compiled, we do not need to compile it each time again. What we have at a certain moment is
therefore pieces of machine code in different files that has to be glued together to a single
program. To solve this problem, the compiler creates tables of the objects and methods
contained in each file. After compilation, the linking and "binding" has to take place. From the
information in all these compiler-generated tables the linker can find the loose ends that need to
be put together, like a method call in one file, where the method is defined in another file.
The picture below illustrates the phases of a compilation process.
#include <iostream>
using namespace std;
int add( int x, int y); // forward declaration using function prototype
int main()
{
cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
return 0;
}
add.cpp:
For compilation, we may compile each file individually, running the compiler with the option that
the code is not complete. Then, we run the compiler with both object files. In Unix (on my mac)
the resulting file is by default called a.out. I can call this file to let it run. See below the command
line steps to compile, link and run the program main.cpp
19
3. program structure in openFrameworks
One of the challenges using openFrameworks is to understand how code is distributed over
files within the programming environment. Lot of what you see in openFrameworks is also present
in Processing, but hidden.
Best is to look at the example you get for the assignment, the maze generator.
• In principle you start each new project in openFrameworks with the project generator. This
results already in a structure of three files given: main.cpp, ofApp.cpp, ofApp.h
• Leave the function main.cpp untouched (except perhaps for windowsize, but that can be
done more elegantly). main() just starts the whole machinery of an openFrameworks project.
• All class definitions are split in two parts: one including all the headers, which here means all
the declarations. This one ends with .hpp or .h. The other one contains the definitions of the
methods etc., this is where the actual implementation of the methods/functions is done.This
one ends with .cpp.
• In App.h there are already a number of variables and functions/methods declared. You
declare all your “global” variables, like the variables you would put above setup() in
Processing. In our maze generation example the App.h the only object declaration added
here is the last: Grid grid; (also # include Grid.hpp is added more on this below).The rest is
already given by the project generator:
App.h:
#pragma once
#include "ofMain.h"
#include "Grid.hpp"
Grid grid;
};
The (beginning of) ofApp.cpp looks as below. Into the part setup go all the initialisations, similar
to Processing. In openFrameworks there are two cyclically executed functions: update() and
draw(), first always update(), then draw().
20
The code added here to the structure given is the initialisation of the random generator and call
of the method generateMaze() for the object grid. In draw() the method draw() for the object grid
is called. In the keyReleased() method a menu to start different methods is added.
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofBackground(255);
grid.generateMaze();
}
//--------------------------------------------------------------
void ofApp::update(){
//--------------------------------------------------------------
void ofApp::draw(){
grid.draw();
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
switch(key) {
case 'm':
grid.reset();
grid.generateMaze();
break;
case 'g':
grid.generateMaze();
break;
case 'd':
grid.depthFirstSearch();
break;
case 'b':
grid.breadthFirstSearch();
break;
}
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
All files other than main.cpp, ofApp.cpp and ofApp.h are added after project generation.
Gridelement.cpp, Gridelement.hpp and also Grid.cpp and Grid.hpp contain class definitions.
Direction.cpp and Direction.hpp contains a type definition and a function.
In Gridelement.hpp you see the class definition as usual, only the “bodies” of the methods are
missing: these are contained in Gridelement.c.
By looking at the example you will understand how the syntax works.
GridElement.hpp:
#ifndef GridElement_hpp
#define GridElement_hpp
#include "Direction.hpp"
class GridElement {
public:
GridElement();
void reset();
GridElement *neighbours[N_DIRECTIONS];
bool walls[N_DIRECTIONS];
#endif /* GridElement_hpp */
22
4. pointers
A pointer is a variable that contains an address. The analogy we use here is the number of a coat
as you get it, e.g., from the checkroom at the theater.
4.2 how to declare a pointer?
As all variables, a pointer has to be declared.
As all variables, a pointer has a type.
The type of the pointer depends on the type of what it is pointing at:
this can be a variable of type int or char or bool or any other.
In our example, assuming that coat is a type,
the type of the checkroom number is a pointer to coat,
and the declaration of a pointer variable my_checkroom_number would be:
coat * my_checkroom_number;
23
int * number_address;
char * character_address;
The first is a pointer with the name number_address that points at a variable of type int.
The second is a pointer named character_address that carries the address of a variable of type
char.
When using pointers, we basically need two operations. In our analogy, these are:
1. For the checkroom number we want to get the coat.
For this purpose we use the dereference operator * . Read * as "points at".
2. For the coat in the checkroom we want to know what its checkroom number is. For this
purpose we use the reference operator &. Read & as "the address of”.
For the following program sequence find out what the values of the
variables firstValue and secondValue are in the end!
p1 = &firstValue;
p2 = &secondValue;
24
*p1 = 10;
*p2 = *p1;
p1 = p2;
*p1 = 20;
return 0;
}
int * p;
p = 0; // p has a null pointer value
or, equivalently
int * p;
p = NULL; // NULL is the null pointer
There are different opinions about whether to use “0” for the null pointer, as in the first example,
or the “NULL” as in the second example.
From a program clarity point of view, the NULL is nicer, because this NULL is
exclusively used for the null pointer, and it visualises directly the context of pointers.
25
2. We can build dynamic data structures, as, e.g., trees, or lists. The point here is that we
often do not know how long a list will be when we write a program - it may be different for
each run of the program - or we do not know how big a tree is. Without pointers we have
to declare an array that is big enough for the worst case. This may be a waste of memory,
and, if we add on all memory wastes for oversizing memory space, we may get slow
programs or programs that do not fit into the memory.
3. Next, we can build data structures that efficiently support the operations we need. For
example, adding an element in a sorted list implemented as an array will probably cost
many shift-operations. With a sorted list implemented by pointers, there are basically two
assignments needed.
An example:
For the function call, the values of a and b,
{
which are 3 and 4, are copied and assigned to the
int a=3;
int b=4; parameters of the function maximum.
int c; The actual variables a and b cannot be changed
by the function called.
c= maximum(a,b);
.....
}
26
example:
in C++ there is made a difference between pointers and references, which does not refer to the
concepts described above.
when we have
int i = 3;
then:
declares point as a pointer to an integer variable and initialises it with the address of i.
On the other hand:
int &ref = i;
declares a variable ref as a reference to an integer variable, initialised with the address of i.
ref is called a reference in contrast to the pointer point above. One difference is an optical
one, which is about the use of the dereference operator:
*point=4; does the same as ref=4;
#include <iostream>
using namespace std;
int main(){
int i = 3;
// this is the declaration of a pointer to an int that is initialised with the address
of i int *point = &i;
// the main difference is that a pointer needs a dereference symbol, the reference
not.
27
// the both statements below do the same
*point=4;
ref=4;
{ int j=5; ref=j; cout << "reference's content is : " << ref <<endl;
cout << "i's content is : " << i <<endl;}
return 0;
}
)
5.4 what was a side effect again?
The side effect of our make-a-cake function is that it has a dirty kitchen as result, which is not
indicated as a result of the function.
28
5.5 reference (pointer) to an object
int main() {
Chip *one_chip = new Chip(2.7f, 3.8f);
cout << "the chip is " << one_chip->length << " long" << endl;
cout << "the chip is " << one_chip->breadth << " broad" << endl;
return 0;
}
an equivalent alternative to
would be
Chip *one_chip;
one_chip = new Chip(2.7f, 3.8f);
29
5.6 pointers and arrays
int numbers[5];
int * p = numbers; // pointer p points at the first array element
*p = 1; // is the same as numbers[0]=1;
p++; *p = 2 // has the same effect as numbers[1]=2;
p = &numbers[2]; // p points now to numbers[2]
*p = 3; // has the same effect as numbers[2]=3
p = numbers + 3; // p points now to numbers[3]
*p = 4;
p = numbers;
*(p+4)= 5; // has the same effect as numbers[4]=5
Pointer arithmetic
mychar++;
myshort++;
mylong++;
30
5.7 pass a reference to an object as parameter for a function.
#include <iostream>
using namespace std;
int main ()
{
// an int array with 5 elements.
int ages[5] = {10,47,18,80,81};
double average;
return 0;
}
31
example: Pass a reference to an object as parameter for a function.
int main() {
32