A Tour of the C++ Programming Language
We already know C Everything that can be done with a computer, can be done in C Why should we learn another language? Newer languages provide a bigger toolbox Some code can be made simpler and shorter using more advanced features In particular, C++ can simplify a lot of the techniques we use in Object Oriented Programming 2
What things bother us when writing C code? Explicit memory management is needed We always have to remember ourselves when to free a resource It cannot be encapsulated (i.e., it is not hidden from the user) void printbeststudents(set students, int mingrade) { Set beststudents = setfilter(students, gradegreater, mingrade); if (beststudents == NULL) { return; List sortedstudents = settolist(beststudents); setdestroy(beststudents); if (sortedstudents == NULL) { return; if (listsort(sortedstudents, studentcomparebygrade) == LIST_SUCCESS)) { LIST_FOREACH(Student, student, sortedstudents) { studentprint(student); listdestroy(sortedstudents); 3
What things bother us when writing C code? Writing code as ADTs results in long names Student findbeststudent(set students) { SET_FOREACH(Student, student, students) { if (studentgetaverage(student) > studentgetaverage(best)) { best = student; return best; 4
What things bother us when writing C code? Generic ADTs (such as our set) Require cumbersome extra code for every type they are used with Require constant use of unsafe pointer casting static char* stringcopy(setelement str); static void stringdestroy(setelement str); static int stringcompare(setelement str1, SetElement str2); Set set = setcreate(stringcopy, stringdestroy, stringcompare); //... setadd(set, student); 5
What things bother us when writing C code? Error handling requires a lot of code It can easily become most of the code Each type has its own unique error codes no natural way to translate between them, merge sets of error codes, etc. GraphResult graphaddedge(graph graph, VertexLabel label1, VertexLabel label2) { GraphResult vertex1exists = vertexexists(graph, label1); GraphResult vertex2exists = vertexexists(graph, label1); if (vertex1exists == GRAPH_OUT_OF_MEMORY vertex2exists == GRAPH_OUT_OF_MEMORY) { return GRAPH_OUT_OF_MEMORY; if (vertex1exists == GRAPH_FAIL vertex2exists == GRAPH_FAIL) { return GRAPH_FAIL; Edge edge = edgecreate(label1, label2); if (edge == NULL) { return GRAPH_OUT_OF_MEMORY; SetResult result = setadd(graph->edges, edge); edgedestroy(edge); return convertsetresult(result); 6
Originally developed by Bjarne Stroustrup from 1979 Back at the time it was called C with classes The intention was to add useful features from Simula on top of C First release in 1983 as C++ The current standard is C++11 C++ is based on C Adds features to simplify object oriented programming And much more Most C code can be compiled as C++ code However, things are done differently in C++! Using C style paradigms in C++ is bad programming 7
C++ is based on C Code looks similar in many cases #include <stdio.h> C #include <iostream> using namespace std; C++ int factorial(int n) { if (n <= 1) { return 1; return n * factorial(n - 1); int factorial(int n) { if (n <= 1) { return 1; return n * factorial(n - 1); int main() { printf("hello World!\n"); printf("5! = %d\n", factorial(5)); return 0; int main() { cout << "Hello world!" << endl; cout << "5! = " << factorial(5) << endl; return 0; 8
Classes are the most notable feature of C++ A class is the way provided by C++ to define new data types and ADTs A C++ class can behave much more like a real type than a C ADT Basically, a C++ class is a struct + functions We will call such functions member functions or methods void f() { Complex c1(3,2), c2; c2 = 2 + 5*COMPLEX_I; class Complex { double real, imag; //... more data fields 9 double x = c1.real(); c1.set_real(2*x); cin >> c2; if (c2.imaginary() < 0) { return; if (abs(c1-c2) < 0.001) { cout << "c1 and c2 are equal!\n << endl; public: double real() const; double imaginary() const; void set_real(double); void set_imaginary(double); //... more methods ;
C++ tries to avoid uninitialized data Classes have special methods to automatically initialize and destruct them, called constructors and destructors These replace the C style create and destroy functions void f() { Complex c1(3,2), c2; c2 = 2 + 5*COMPLEX_I; double x = c1.real(); c1.set_real(2*x); cin >> c2; if (c2.imaginary() < 0) { return; 10 if (abs(c1-c2) < 0.001) { cout << "c1 and c2 are equal\n << endl;
Destructors are extremely useful The compiler automatically calls the destructor when a local object is released This is a major difference from C allows a class to fully encapsulate resource management! void f() { 11 Complex c1(3,2), c2; c2 = 2 + 5*COMPLEX_I; double x = c1.real(); c1.set_real(2*x); cin >> c2; if (c2.imaginary() < 0) { return; if (abs(c1-c2) < 0.001) { cout << "c1 and c2 are equal\n << endl; class Complex { double real, imag; //... more data fields public: Complex(); ~Complex(); double real() const; double imaginary() const; //... more methods ;
C++ allows defining custom operators for classes For example, a complex number type can be made to work with +, -, *, / and more void f() { Complex c1(3,2), c2; c2 = 2 + 5*COMPLEX_I; double x = c1.real(); c1.set_real(2*x); cin >> c2; if (c2.imaginary() < 0) { return; 12 if (abs(c1-c2) < 0.001) { cout << "c1 and c2 are equal\n << endl;
C++ allows creation of generic code using a template mechanism Template code is checked by the compiler for correctness No need to mess with all function pointers explicitly set<string> strings; string input; while (cin >> input) { if (input == "stop") { break; strings.insert(input); Complex one(1.0, 0.0); strings.insert(one); 13
C++ supports inheritance - creating a class B which inherits the behavior of class A Allows creating polymorphic interfaces very easily class Shape { public: virtual double getarea() const; virtual double getperimeter() const; ; class Square : public Shape { public: virtual double getarea() const; virtual double getperimeter() const; ; array<shape*> shapes = { new Square(3.0), new Circle(1.0), new Rectangle(2.0, 4.0) ; double area = 0.0; double maxperimeter = 0.0; for (int i = 0; i < shapes.size(); ++i) { area += shapes[i].getarea(); cout << "The total area is << area << endl; 14
C++ supports error handling using an exception mechanism Provides a way for a function to terminate with an error (an exception object), without using return Exceptions require writing code only where the error occurs (thrown) or handled (caught) void f() { //... try { cin >> x; update_values(values,size,x); catch (DivideByZeroException& e) { cerr << "Division by zero!"; void update_values(complex values[], int size, double x) { for (int i = 0; i < size; i++) { values[i] = values[i] / x; Complex operator/ (Complex a, Complex b) { if (b==0) { throw DivideByZeroException(); //... do actual computation 15
C++ comes with a Standard Template Library Contains many data structures and algorithms Can be easily extended to cooperate with user code int main(int argc, char **argv) { vector<int> v = { 5, 4, 1, 2, 3 ; sort(v.begin(), v.end()); list<int> l(v.begin(), v.end()); if (find(l.begin(), l.end(), 4)!= l.end()) { cout << "found" << endl; return 0; 16
C++11 is a fairly new standard As such, it is not fully implemented yet The latest version of G++ (GCC s C++ compiler) handles almost all of the standard's features Features which are C++11 only will be marked You can solve your homework using these C++11 features, but it s not mandatory 17
C++ is much more advanced than C Takes more time to master However: DON T PANIC Understanding even only the basic features can simplify a lot of your work 18
C++ is similar to C However, there are some elementary differences We will first cover a few of enhancements needed before we can move on 19
C++ has the const keyword which is used as in C99 We will see that const is used much more widely in C++ const int n = 5; const int* ptr = &n; int* const cptr = &n; // error const int* const cptr2 = &n; Const correctness is about indicating which objects change and which don't, and ensuring consistency The goal is letting the compiler (and reader) find errors easily 20
C++ allows defining a reference to a variable The notation T& means reference to type T A reference acts as an alternative name for a variable int i = 1; int& r = i; int x = r; r = 2; 21
References must be initialized int& r; Once initialized, a reference target cannot be changed int ii = 0; int& rr = ii; rr++; int* pp = &rr; A reference is similar to a constant pointer However, a reference isn't an object that can be manipulated like a pointer A reference always refers to a legal object 22
References can be used as function arguments Can be used when a function has to modify its arguments void swap(int& a, int& b) { int temp = a; a = b; b = a; int a = 5; int b = 3; swap(a, b); Like the address-of operator &, a reference cannot refer to a temporary value or a constant swap(a, 3); swap(a, x + y); 23
References can also be used as a return value int& max(int array[], int size) { int maxindex = 0; for(int i = 1; i < size; i++) { if (array[i] > array[maxindex]) { maxindex = i; return array[maxindex]; References can serve as a left-hand-side (LHS) in assignment This seems weird for now, but has many natural uses int array[] = { 1, 3, 4, 2, 5 ; max(array, 5) = 7; 24
A reference can be declared to refer to a const In this case the object referenced cannot be changed through the reference A const reference can refer to a temporary value void print(const int& r) { cout << r << endl; int a = 5; print(3); print(3 + a); 25
C++ allows definition of several functions with the same name The functions are overloaded on the name These functions must have different enough parameters The compiler chooses the function which fits best void swap(int&, int&); void swap(double&, double&); int a, b; double c,d; swap(a,b); // calls first swap swap(c,d); // calls second swap swap(a,c); // syntax error 26
C++ allows defining a default value for a function argument The function may be called without this argument, in which case the default value is passed Several of the arguments may have default values, but they must be the last ones static void printnumbers(int to = 10) { for (int i = 0; i < to; ++i) { cout << i << ", "; cout << endl; printnumbers(5); printnumbers(); // printnumbers(10); or num_utils.h void printnumbers(int to = 10); num_utils.c void printnumbers(int to) { for (int i = 0; i < to; ++i) { cout << i << ", "; cout << endl; 27
Default arguments are useful when one of the arguments has a common value which is used frequently void sort(int array[], int size, int (*compare)(int, int) = compareints) { for (int i = 0; i < size; ++i) { for (int j = 0; j < size - 1; ++j) { if (compare(array[j], array[j + 1]) > 0) { swap(array[j], array[j + 1]); int compareints(int a, int b) { return a - b; int compareinverse(int a, int b) { return b - a; int array[] = {3, 4, 2, 1, 5; int size = sizeof(array) / sizeof(array[0]); sort(array, size); // sort(array, size, compareints); sort(array, size, compareinverse); 28
There is no implicit cast from void* to other pointers in C++ C++ has better mechanisms in order to avoid the need of such casts Pointer casting should be avoided in C++ There are better solutions int* ptr = malloc(sizeof(*ptr)); int* ptr = (int*)malloc(sizeof(*ptr)); 29
Memory allocations are done in C++ using the new and delete operators new & delete are typed Unlike malloc and free, which use void* new initializes an object, and delete calls its destructor So there is no uninitialized memory containing garbage Built in types (such as int) can still be allocated without initialization if needed int* ptr = malloc(sizeof(*ptr)); *ptr = 5; int* array = malloc(sizeof(*array) * 10); //... need to verify allocations... C int* ptr = new int(5); int* array = new int[10](); //... C++ free(ptr); free(array); delete ptr; delete[] array; 30
All code in C++ is divided into a hierarchical structure of namespaces Think of namespaces like folders in a file system namespace fast_math { double sqrt(double); double cos(double); double sin(double); void f(double& d) { cout << std::sqrt(d) << endl; cout << fast_math::sqrt(d) << endl; 31
Namespaces can be nested namespace mtm { namespace ex4 { enum ErrorCode { OUT_OF_MEMORY,... ; printerror(errorcode e); mtm::ex4::printerror(mtm::ex4::out_of_memory); std::cout << "Error!" << std::endl; A using statement can be used to define which implementation we want in this part of the code using std::cout; using std::endl; using namespace mtm::ex4; printerror(out_of_memory); cout << "Error!" << endl; 32
The C language combines all the power of assembly language with all the ease-of-use of assembly language. - Mark Pearce 33