CITS2002 Systems Programming
1 next ¡ú CITS2002 CITS2002 schedule
The Hello World program in C++
Let’s first consider the basic (anticipated) Hello World program written in C++.
As with many of the examples in this lecture, we will compare C++’s different features with equivalent ones of C11:
#include
int main(void) {
std::cout << "Hello, world!\n";
return 0; }
Important points from this example:
#include
C++ source code is first passed through the same preprocessor as are C11 programs. Here, one of the standard C++ header files (with a similar role to C11’s
std::cout << string;
This statement outputs a text string (similar to C11) to a character output stream. The destination for the string is the std::cout stream, akin to stdout in C11. The << operator is not a bit-wise shift (as in C11), but indicating that the string is 'appended' to the stream.
What is std:: ?
In C++, identifiers can be defined within a context, similar to a directory of identifiers, termed a namespace. When we want to access an identifier defined in a namespace, we tell the compiler to look for it in that namespace using the scope resolution operator (::). Here, we're telling the compiler to look for cout in the std namespace, in which many standard C++ identifiers are defined. A cleaner alternative is to use:
using namespace std;
This line tells the compiler that it should look in the std namespace for any identifier we
haven't defined. We can omit the std:: prefix when writing cout.
CITS2002 Systems Programming, Lecture 22, p1, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 2 next¡ú CITS2002 CITS2002schedule
Standard cin and cout I/O streams
Similar to C11's use of its standard I/O header file and library functions, C++ employs its
iostream header and functions.
A little confusingly, it is possible to mix C11 and C++ I/O in the same programs, but it's not
always safe to mix them in the same statement.
#include
using namespace std;
int main(void) {
int x; cin >> x;
cout << x/3 << ' ' << x*2;
return 0; }
In particular, many programmers moving from C11 to C++ prefer C11's printf() family of functions, over C++'s use of appending strings to a file-stream:
#include
using namespace std;
void printVector(double x0, double x1, double y0, double y1)
// equivalent to C11’s printf(“(%f,%f) -> (%f,%f)\n”, x0, y0, x1, y1);
cout << "(" <<
x0 << "," << y0 <<
<< x1 << "," << y1 <<
")" << endl;
CITS2002 Systems Programming, Lecture 22, p2, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 3 next¡ú CITS2002 CITS2002schedule
Function Overloading
In C11, if we wish to perform very similar operations, but on different datatypes, we need to define multiple functions, with different (but similar) names.
In contrast, C++ supports function overloading which permits functions with the same name to support different parameter types and different return types.
This is often termed "a function with multiple type-signatures"
#include
void outputWithNewline(int x) {
cout << "Integer value: " << x << endl; }
void outputWithNewline(char *x) {
cout << "String value: " << x << endl; }
The C++ compiler recognises that the multiple functions are strongly related, and calls the correct function (generates the correct instructions) depending on how the functions are called (i.e. with what parameter types).
CITS2002 Systems Programming, Lecture 22, p3, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 4 next¡ú CITS2002 CITS2002schedule
Passing parameters by reference
Recall that when we introduced pointers in C11, we used an example attempting to swap the values of two function parameters. Because the parameters were passed by value (a copy of them was made), the original memory destinations (provided when the function was called) were not changed:
#include
// Unsuccessful at swapping values
void swapints1(int a, int b) {
inttmp = a;
b = tmp; }
To address the problem, we employed the address-of operator so that the function would have access to the (original) memory locations. the result, however, was additional (confusing) punctuation:
#include
// Successful at swapping values when called as swapint2(&x, &y);
void swapints2(int *a, int *b) {
int tmp = *a;
*b = tmp; }
To address this confusion, C++ introduces pass-by-reference parameters, which ‘invisibly’ treats parameters as pointers, without the additionsl syntax for dereferencing identifiers. Note that
C++ still permits C11’s dereferencing operator, and the code may be safely mixed within statements:
#include
void swapints3(int &a, int &b)
// Successful at swapping values when just called as swapint3(x, y);
inttmp = a; a = b;
b = tmp; }
CITS2002 Systems Programming, Lecture 22, p4, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 5 next¡ú CITS2002 CITS2002schedule
Classes and internal methods
As with other object-oriented languages, C++ ‘collects’ strongly related data and functions operating on that data in classes.
C++ classes may legally have only data members (fields), with no internal methods, and they are then very similar to C11’s structures.
In this example, the class MyVector has two public methods that have access to the class’s data members.
They can access or modify the values associated with an instance of the class.
#include
class MyVector { public:
Point start;
Point end;
void offset(double offsetX, double offsetY) { start.x += offsetX;
end.x += offsetX;
start.y += offsetY;
cout << <<
+= offsetY;
print(void) {
"(" << start.x << "," << start.y << ") -> (” end.x << "," << end.y << ")" << endl;
Note that the methods offset() and print() are internal to the class definition and, thus, act as both declarations and definitions of the methods.
CITS2002 Systems Programming, Lecture 22, p5, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 6 next¡ú CITS2002 CITS2002schedule
Classes with methods defined externally
As with functions in C11, we can separate the declarations and definitions of C++ methods. As with C11, we employ header files to provide the declarations - this 'thing' exists elsewhere,
and then define (implement) the method in a C++ source file:
#include
// myvector.h – header file
class Point { public:
double x, y;
void offset(double offsetX, double offsetY);
void print(void); };
class MyVector { public:
Point start, end;
void offset(double offsetX, double offsetY);
void print(void); };
CITS2002 Systems Programming, Lecture 22, p6, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 7 next¡ú CITS2002 CITS2002schedule
Classes with methods defined externally, continued
Here, the class’s methods are defined ‘away’ from their declarations in the header file. Thus, we need to preface each method name with the name of class to which it belongs. To ensure that the defintions are type-compatible with the class’s declarations, we use the preprocessor to include the class definition:
Here, we can think of Point as the namespace to which the methods belong:
#include
// myvector.cpp – method implementation
void Point::offset(double offsetX, double offsetY) {
x += offsetX; y += offsetY; }
void Point::print(void) {
cout << "(" << x << "," << y << ")"; }
void MyVector::offset(double offsetX, double offsetY) {
start.offset(offsetX, offsetY);
end.offset(offsetX, offsetY); }
void MyVector::print(void) {
start.print();
cout << " -> “;
end.print();
cout << endl;
CITS2002 Systems Programming, Lecture 22, p7, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 8 next¡ú CITS2002 CITS2002schedule
Initialising the data members of a class with constructors
In most C11 programs, when introducing a new variable (often near the top of a block of statements) we immediately follow the introduction by multiple statements which initialise the variable.
#include
MyVector vec;
vec.start.x = 0.0;
vec.start.y = 0.0;
vec.end.x = 0.0;
vec.end.y = 0.0;
p.x = 0.0;
p.y = 0.0;
If a scalar variable, this presents little problem, but for structures or arrays, we must ensure that the initial value is ‘suitable’, and that we don’t miss any values.
This is often achieved with an additional function, defined physically ‘close’ to the definition of the structure or array datatype.
In C++, as with most object-oriented languages, we can combine the class’s fields (internal variables) with a method to initilise them. This special method, termed a constructor, doesn’t require any ‘external’ code to have knowledge of the implementation of the class, or how its fields are initialised.
A constructor is a method that is called when a class instance is created.
#include
class Point {
double x, y;
Point(void) {
x = 0.0; y = 0.0;
cout << "Point instance created" << endl;
int main(void) {
Point p; // Point instance created
// p.x is now 0.0, p.y is now 0.0 }
#include
class Point {
double x, y;
Point(double nx, double ny) {
x = nx; y = ny;
cout << "2-parameter constructor" << endl;
int main(void) {
Point p(2.0, 3.0); // 2-parameter constructor // p.x is 2.0, p.y is 3.0
CITS2002 Systems Programming, Lecture 22, p8, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 9 next¡ú CITS2002 CITS2002schedule
Multiple contructors using function overloading
Previously we saw that C11 permits a single function 'name' to have multiple type-signatures - multiple functions with same name, but with different sets of parameters.
The same concept applies to class constructors - a class may have multiple constructors (each named after the class), that permits an instance of the class to be created and initialised in different ways:
#include
class Point { public:
double x, y;
Point(void) {
x = 0.0; y = 0.0;
cout << "default constructor" << endl;
Point(double nx, double ny) {
x = nx; y = ny;
cout << "2-parameter constructor" << endl;
int main(void) {
Point p; // default constructor // p.x is 0.0, p.y is 0.0
Point q(2.0, 3.0); // 2-parameter constructor
// q.x is 2.0, q.y is 3.0 }
CITS2002 Systems Programming, Lecture 22, p9, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 10 next¡ú CITS2002 CITS2002schedule
Scoping and Memory
Recall some important issues with C11 and memory allocation for identifiers:
Whenever we declare a new variable, such as int x, memory is allocated
When can this memory be freed up (so it can be used to store other variables)?
When the variable goes out of scope
When a variable goes out of scope, that memory is no longer guaranteed to store the variable's value
C++'s new operator
C++ provides another mechanism to allocate memory, which will remain allocated until
manually de-allocated.
This is very similar to C11's malloc family of functions.
The new operator returns a pointer to the newly allocated memory:
If using int x; the allocation occurs on the run-time stack,
If using new int; the allocation occurs within theheap. C++'s delete operator
In a manner similar to C11's free() function, C++'s delete operator de-allocates memory that was previously allocated using new
#include
int *x = new int;
#include
int *x = new int;
// use memory allocated by new ….
CITS2002 Systems Programming, Lecture 22, p10, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 11 next¡ú CITS2002 CITS2002schedule
Dynamically allocating memory for arrays
If we use new[] to allocate arrays, they can have variable size
#include
int numItems;
cout << "how many items?";
cin >> numItems;
int *arr = new int[numItems];
We then de-allocate arrays with delete[] :
Allocating class instances
new can also be used to allocate a class instance The appropriate constructor will be invoked
delete[] arr;
#include
class Point { public:
Point(void) {
x = 0; y = 0;
cout << "default constructor" << endl;
int main(void) {
Point *p = new Point; ....
The appropriate constructor will be invoked.
#include
class Point { public:
Point(int nx, int ny) {
x = ny; x = ny; cout << "2-arg constructor" << endl; }
int main(void) {
Point *p = new Point(2, 4); delete p;
CITS2002 Systems Programming, Lecture 22, p11, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 12 next¡ú CITS2002 CITS2002schedule
Class destructors
A class destructor is called when the class instance is de-allocated
If the class was allocated with new, when delete is called, and
If allocated on the runtime stack (introduced in a block of statements), when the identifier goes out of scope.
#include
classs Point { public:
Point(void) {
cout << "constructor invoked" << endl;
~Point(void) {
cout << "destructor invoked" << endl;
CITS2002 Systems Programming, Lecture 22, p12, 18th October 2021.
CITS2002 Systems Programming
¡ûprev 13 next¡ú CITS2002 CITS2002schedule
File streams
File handling in C++ works almost identically to terminal input/output. To use files, we #include
ifstream : allows reading input from files
ofstream : allows outputting to files
Each open file is represented by a separate ifstream or an ofstream object.
You can use ifstream objects in exactly the same way ascin and ofstream objects in the same way as cout, except that you need to declare new objects and specify what files to open.
#include
using namespace std;
int main(void) {
ifstream source(“source-file.txt”); ofstream destination(“dest-file.txt”);
source >> x; // Reads one int from source-file.txt
source.close(); // close file as soon as we’re done using it
destination << x; // Writes x to dest-file.txt
} // close() called on destination by its destructor
CITS2002 Systems Programming, Lecture 22, p13, 18th October 2021.
CITS2002 Systems Programming
¡û prev 14 CITS2002 CITS2002 schedule
C++ Templates
We have seen that functions can take arguments of specific types and have a specific return type. We consider templates, which allow us to work withgeneric types.
#include
int add(const int x, const int y) { return x + y;
int add(const double x, const double y) { return x + y;
Using templates, rather than repeating function code for each new type we wish to support, we create a ‘generic’ function that performs the same operation independent of the types of its parameters.
#include
template
T add(const T a, const T b) {
return a + b; }
The Standard Template Library (STL)
Part of the C++ Standard Library, the Standard Template Library (STL) contains many useful container classes and algorithms. As you might imagine, these various parts of the library are written using templates and so are generic in type. The containers found in the STL are lists, maps, queues, sets, stacks, and vectors. The algorithms include sequence operations, sorts, searches, merges, heap operations, and min/max operations.
The STL has many, many more containers and algorithms that you can use. Great reference material:
http://www.cplusplus.com/reference/stl and ://www.cplusplus.com/reference/algorithm/.
CITS2002 Systems Programming, Lecture 22, p14, 18th October 2021.