You are on page 1of 56

Warm-up & hands-on

Start now to use STL... (crucial) ! #include <algorithm> : copy, sort, min_element, max_element ! #include <string> : string ! #include<vector>, #include<set>, #include <map> ! #include <fstream>: istream, ostream ! http://www.cplusplus.com/reference/
! many,

fine-grained iterations: extend XOR refactor the code (doesnt compile) fix compilation problems (doesnt run properly) fix bugs (is not ready to be extended) the crude truth... ...it is not the computer. Humans are sloppy.

! accept

Friday, May 3, 2013

Today:

Polymorphism Virtual functions Abstract base classes Generic functions

Friday, May 3, 2013

Base Classes and Derived Classes


! One

key element of OO programming is inheritance: A new class can inherit the data members and member functions of a previously defined class (and add new ones).

! Example:

ETH-Members, Student, Professor, Assistant Students, professors, and assistants are ETH-Members.
! Example:

Triangles, Circles, Rectangles are Shapes.

Friday, May 3, 2013

Base Classes and Derived Classes


! We

work out an example with base class Employee, and derived class Manager. ! Important: Keep in mind that every Manager is an Employee but not every Employee is a Manager. An object of a derived class can be treated as an object of the corresponding base class. ! A derived class cannot access the private members of its base class. ! A derived class constructor can always call the constructor for its base class.

Employee

Manager

Friday, May 3, 2013

The base class


class Employee { Constructor (initializer list) public: Employee(string n) : name_(n) {}; void print_info() const {cout << "Name: " << name_ << endl;} string get_name() const {return name_;}; private: Member functions. const: guarantee that name_ is not modied string name_; };
Access specier Data member

Friday, May 3, 2013

A derived class

Class Manager inherits from class Employee

class Manager : public Employee { public: The base class constructor is called explicitly Manager(string name, string dep) : Employee(name), department_(dep) {}; void print_info() const { Base class function call Employee::print_info(); cout << "Head of the " << department_ << endl; } An additional (manager specic) private data member private: string department_; };

Friday, May 3, 2013

A client

int main() { string employee_name = "Simpson"; Employee worker(employee_name); string boss_name = "Mr. Burns"; string comp_name = "Nuclear Power Plant"; Manager boss(boss_name, comp_name); worker.print_info(); boss.print_info(); // Name: Simpson // Name: Mr. Burns Head of the Nuclear Power Plant

Employee* base_ptr = &boss; base_ptr->print_info(); // what will this print? };


Friday, May 3, 2013

Base class pointers

Employee* base_ptr = &boss; base_ptr is a pointer variable to an object of class Employee and its value is the address of the boss object. This is correct, since every object of type Manager can be treated as an Employee. The variable base_ptr is called a base class pointer. functions and data members can be addressed using the dot notation, but for pointers the arrow notation is more convenient: worker.print_info(); base_ptr->print_info(); (*base_ptr).print_info();

! Member

// equivalent

Friday, May 3, 2013

The C++ rule

The data type of the pointer determines which objects member function is called NOT the data type of the object the pointer currently points to!

Friday, May 3, 2013

Overview Which function is called??

Employee void print_info() const string get_name() const name_

Employee a; a.print_info(); Manager b; cout << b.get_name(); b.print_info(); b.Employee::print_info(); Manager c; Employee* ptr = &c; ptr->print_info();

Manager void print_info() const department_

Friday, May 3, 2013

What if we want the member function of the object actually pointed to to be called?

Friday, May 3, 2013

The 3 core concepts of OOP

Encapsulation
in C++: Classes, Objects and Access Specifiers (private, public, ...)

Hierarchical Classification
in C++: Subclasses and Inheritance

Polymorphism
in C++: Overloading and Overriding, virtual functions and abstract base classes

Friday, May 3, 2013

Polymorphism

One interface, multiple methods

Friday, May 3, 2013

Types of Polymorphism

Compile-time

(early binding)

in C++: Operator overloading, function overloading (see earlier!)


Run-time

(late binding)

in C++: virtual functions, pure virtual functions, base class pointers, abstract base classes

Friday, May 3, 2013

Ingredients of Polymorphism

Ingredient #1:

Base class pointers

Friday, May 3, 2013

Base class pointers

A pointer to the base class can point to any object of derived sub-classes. (remember: if A is a subclass of B, then A is a B.)

Base_class *p; // pointer to object of class Base_class Base_class base_obj; // object of class Base_class Sub_class sub_obj; // object of a sub-class p = &base_obj; p = &sub_obj; // p points to base class object // p points to sub-class object

Any inherited elements in the sub-class can be accessed through the pointer. Elements specific to the sub-class cannot!

Friday, May 3, 2013

Base class pointers: Example

#include <iostream> #include <string> class B_class { char author[80]; public: void put_author(char *s) { strcpy(author, s); } void show_author() { cout << author << endl; } }; main() { B_class *p; // pointer to class B_class B_obj; p = &B_obj; // let p point to object // access member function through pointer: p->put_author(William Shakespeare); p->show_author(); // WHAT WILL THIS PRINT ? }

Friday, May 3, 2013

Base class pointers: Example

Consider the following sub-class:


class D_class : public B_class { char title[80]; public: // read and write the private property void put_title(char *s) { strcpy(title, s); } void show_title() { cout << title << endl; } };

The base class pointer can also point to a sub-class object:


B_class *p; // pointer to class D_class D_obj; // object of sub-class ..... p = &D_obj; // this is OK! P->put_author(Stanislav Lem); // OK P->put_title(Solaris); // THIS IS WRONG !

Friday, May 3, 2013

Base class pointers: Properties


A base class pointer can point to any object of a derived sub-class, but the reverse it not true:
B_class B_obj; D_class D_obj; D_class *dp; dp = &D_obj; dp = &B_obj; // // // // // base class object object of sub-class pointer to sub-class this is OK! THIS IS WRONG !

Elements only defined in the sub-class can not be accessed through the base class pointer. The increment operator will not work correctly if the base class pointer actually points to an object of a sub-class. => ..dangerous, TIP OF THE ICEBERG !

Friday, May 3, 2013

Polymorphism: The Problem

Let both the base class and its sub-class have the same function declaration but with different implementations. A base class pointer can point to an object of either class. If the function is called through such a pointer, which implementation is executed?

Friday, May 3, 2013

Ingredients of Polymorphism

Ingredient #2:

Virtual functions

Friday, May 3, 2013

Virtual functions

If a function is declared as virtual, each derived class can have its own implementation of it. When called through a base class pointer, the class of the object pointed to determines which version of the function is called We thus have run-time polymorphism. A class that includes a virtual function is called a polymorphic class. A class that inherits from a polymorphic class is automatically also polymorphic.

Friday, May 3, 2013

Virtual functions: Example


class Base { public: // who function in the polymorphic base class virtual void who() { cout << Base class << endl; } }; class Derived : public Base { public: // is automatically virtual by inheritance void who() { cout << Derived class << endl; } }; main() { Base *p; // Base base_obj; Derived derived_obj; p = &base_obj; // p->who(); // p = &derived_obj; // p->who(); // }

pointer to base class let p point to base object will print Base class let p point to derived object will print Derived class

Friday, May 3, 2013

Beware This is not function overloading! Since:


Overloaded functions have different declarations (argument lists). Virtual functions must have exactly the same declarations. Redefining a virtual function in a derived class is called Overriding. Virtual functions that have different declarations lose their polymorphic nature and are simply overloaded. careful with const...

Friday, May 3, 2013

Virtual functions: Properties


Virtual functions must always be class members Destructors can be virtual (must?) Constructors can not be virtual Virtual functions can still be called also without using a pointer, but then there is no polymorphic effect:
base_obj.who(); derived_obj.who(); // prints Base class // prints Derived class

Friday, May 3, 2013

Virtual functions: Inheritance

The virtual attribute is inherited. Once a function is declared virtual, it remains virtual, no matter how many layers of derived classes it has been passed through. The virtual keyword does not have to be repeated in the derived sub-classes. If a sub-class does not override a virtual function, the implementation of the closest higher class will be used.

Friday, May 3, 2013

Virtual functions: Use and Advantages

Functions that will be common to all subclasses can be declared by the base class in a single place. The base class dictates the interface for all derived classes, but the latter can have their own actual implementations. (One interface, multiple methods) Helps to develop complex programs or libraries since one can be sure that all derived classes can be accessed using the same function interface (even if they do completely different things).

Friday, May 3, 2013

Virtual functions: An Application


Lets develop a program that handles geometric objects and calculates their areas. First, we define a base class:
#include <iostream> class Shape { protected: // accessible also to sub-classes double x, y; // dimensions of shape public: void set_dim(double i, double j) { x = i; y = j; } // set dimensions virtual void show_area() { // print area // not defined in base class, since type of shape // is unknown here! Still we declare the function // to make assure that all shape sub-classes will // have this method. cout << Not defined. << endl; } };
Friday, May 3, 2013

Virtual functions: An Application


Then we define sub-classes for triangles and rectangles:
// sub-class Triangle inherits from base class Shape class Triangle : public Shape { public: // This function is still virtual and we have to use // exactly the same interface as in the base class void show_area() { cout << Area of Triangle: << 0.5*x*y << endl; } }; // sub-class rectangle in the same way Class Rectangle : public Shape { public: // function is virtual void show_area() { cout << Area of rectangle: << x*y << endl; } };

Friday, May 3, 2013

Virtual functions: An Application


The main program would be:
main() { Shape *p; Triangle t; Rectangle r;

// base class pointer to Shape // on object of class Triangle // on object of class Rectangle

if (user_wants_triangle) { p = &t; // let pointer point to Triangle t } elseif (user_wants_rectangle) { p = &r; // point to Rectangle r } p->set_dim(10.0, 5.0); // define dimensions of shape. p->show_area(); // print area of shape (whatever it is) return 0;

Friday, May 3, 2013

Virtual functions: An Application


What if we want to extend the application to circles ?
// sub-class Circle inherits from base class Shape class Circle : public Shape { public: void show_area() { cout << Area of Circle: << 3.141*x*x << endl; } };

Where is the problem ? User does not know whether to pass the radius as the first or the second argument.

Friday, May 3, 2013

Virtual functions: An Application


Two possible solutions:

Call Circle::set_dim with repeated first and second argument. => Bad idea as it violates the philosophy of Polymorphism Give the second argument a default value in the base class:

// in Shape replace set_dim with: void set_dim(double i, double j=0) // in main one can then simply do: Circle c; p = &c; p->set_dim(9.0); p->show_area();
Friday, May 3, 2013

Another Problem

what happens if someone defines a sub-class of Shape and forgets to implement the show_area() function?

Friday, May 3, 2013

Another Problem
class Shape { protected: double x, y; // dimensions of shape public: void set_dim(double i, double j) { x = i; y = j; } // set dimensions virtual void show_area() { // print area // not defined in base class, since type of shape // is unknown here! Still we declare the function // to make assure that all shape sub-classes will // have this method. cout << Not defined. << endl; } };

Its object will print Not defined since it inherits the virtual function from the base class.

..and you do not get notified by the compiler.


Friday, May 3, 2013

Another Problem

The solution: Force the sub-class to implement the corresponding function by declaring it pure virtual.

Friday, May 3, 2013

Pure Virtual functions

A pure virtual function has no definition in the base class and all derived classes inheriting it are forced (otherwise the program will not compile) to implement it using exactly the given interface. Syntax:
virtual return-type function-name(argument-list) = 0;

A class that contains at least one pure virtual function is called an abstract base class.

Friday, May 3, 2013

Abstract Base Classes


No objects can be instantiated from an abstract base class (since function implementations lack). Sub-classes derived from it need to implement all pure virtual functions. Objects can only be instantiated from sub-classes of it. Base class pointers can still be declared on abstract base classes (but not initialized!):
Abstract_base a; Abstract_base *p; Derived b; p = &a; p = &b; // ERROR // OK // NOT OK // OK

Friday, May 3, 2013

Abstract Base Classes: Example


In our previous example, the Shape base class can be made abstract:
// This is now an abstract base class class Shape { protected: double x, y; // dimensions of shape public: void set_dim(double i, double j) { x = i; y = j; } // set dimensions virtual void show_area() = 0; // pure virtual // has no implementation in the abstract base class };

Every particular sub-class defining an actual shape now has to implement the show_area function.
Friday, May 3, 2013

Advise

Use run-time polymorphism (late binding) whenever meaningful (typically only the case in sufficiently large and complex programs), but not by default. The reason is that late binding is slower than early binding and your program will lose performance (compiler cannot optimize as decision is taken only at runtime). In other words: Use the power, but dont abuse it. (but your only goal is: cut the development time)
Friday, May 3, 2013

Back to our initial example: Virtual Functions


" Polymorphism: ability for objects of different classes related by inheritance to respond differently to the same message (member function call) " Implementation through use of virtual functions. If a virtual function is accessed through a base class pointer, the "right" function is automatically chosen. Manager c; Employee* ptr = &c; ptr->print_info(); Employee / Manager virtual void print_info() const

" Polymorphism promotes extensibility!

Friday, May 3, 2013

Summary: Abstract Base Classes

" A class is made abstract by declaring one or more of its members pure virtual. " virtual return-value function() = 0; // pure virtual " You cannot instantiate an object of an abstract class, but you can derive a new class and provide a definition for pure virtual functions. " Abstract classes are very useful to specify interfaces. All functions in the hierarchy must use the same interface, and provide their own implementation.

Friday, May 3, 2013

Generic Programming

Friday, May 3, 2013

What is generic programming?

Idea: Programs encode action (algorithms,


procedures, instructions for a machine). The type of data they act upon may vary. Particularly, an algorithm could be capable of acting on more than one data type. Example: The Quicksort algorithm can sort any sequence of entities among which a pairwise comparison operator is defined.

Friday, May 3, 2013

What is generic programming?

But: Any particular implementation of an


algorithm using classical programming limits it to one specific data type.

If we implement an algorithm, we have to write some sort of source code and all the variables will be of a specific data type. Example: An implementation of the Quicksort algorithm in C could for example use real variables. This implementation will then only be able to sort sequences of real values.

Friday, May 3, 2013

What is generic programming?

This wastes one of the most precious features of an algorithm: its generality!
In practice we will end up writing the same algorithm several times for different data types. (and maybe we use function overloading to provide a consistent interface).

Friday, May 3, 2013

What is generic programming?

All of these implementations will be exactly the same, except for the data type specifiers. (int,
double, char, )

Have the compiler do this for us !!


In principle its very simple: All we need is a syntactical way to tell the compiler which words in the code to replace to generate a new overloaded version

Friday, May 3, 2013

The central idea of generic functions

Use the same function implementation for different data types without having to explicitly recode specific versions for different types of data.

Friday, May 3, 2013

Generic functions
Generic functions define the general set of operations that can be applied to various data types. The specific data type the function will operate upon is passed to it as a parameter. The compiler will automatically generate the correct specific code for the type of data that is actually used. A generic function can be thought of as a function that overloads itself on demand. A specific instance of a generic function (i.e. compilergenerated for a specific data type) is called a generated function.

Friday, May 3, 2013

C++ syntax for generic functions

Generic functions are created using the keyword template: class

template <typename DataType> return-type func-name(arguments) { // body }

It defines the template of a function implementation and the compiler will automatically fill in the correct data type wherever the DataType placeholder appears. The placeholder is declared by the typename keyword.

Friday, May 3, 2013

Generic functions: Example

#include <iostream> // generic abs function for any numeric data type // the placeholder data type is called X template <typename X> X abs(X value) { // return the absolute value using the // ternary ? Operator (have you seen this before?) return value < 0 ? value : value; } main() { cout cout cout cout }

<< << << <<

abs(-10) << endl; abs(-10.0) << endl; abs(-10L) << endl; abs(-10.0F) << endl;

// // // //

int double long int float

return 0;

Friday, May 3, 2013

Generic functions: Example

What will happen if we call our abs function with a character argument?
cout << abs(`a`) << endl;

It will just print `a` on the screen since a character is nothing but an integer between 0 and 255 (ASCII code)!

What happens for a string argument?


cout << abs(gaga) << endl;

The compiler complains with something like: Wrong type argument to unary minus.

Friday, May 3, 2013

Generic functions: Advantages

Generic functions work for all data types for which they possibly can. Even for those being added to the language later and for those you did not think about when implementing the function (but maybe some smart user of your function will utilize them anyway). Only as many overloaded version as actually used in a specific program are generated (and not all that could possibly be used). You save a lot of typing by not having to overload functions manually. Less error-prone than manual overloading (copy-paste errors). Your code is more readable, less cluttered, and more maintainable (fixes only in one place).

but..nasty compiler messages!


Friday, May 3, 2013

Functions with more than one generic type

More than one generic data type can be defined in the template statement using a comma-separated list:
template <typename type1, typename type2> void myfunc(type1 x, type2 y) { // body }

The type-to-argument assignment in the parameter list defines how the compiler interprets function calls:
myfunc(10, hi) // type1 will be int, type2 char*

Friday, May 3, 2013

Attention: Syntax !
The template keyword and the function declaration do not need to be on the same line. This is perfectly valid:
template <typename type1> void myfunc(type1 x) { // body }

However: NO other statements must occur between the template statement and the function declaration. This will not compile:
template <typename type1> int i; // SYNTAX ERROR ! void myfunc(type1 x) { // body }

Friday, May 3, 2013

Generic functions: Explicit overloading

Although a generic function overloads itself you can still manually overload it explicitly if needed. The explicit overload then overwrites the generic function only relative to that specific data type version (Specialization). Hence you can accommodate exceptions for which the general algorithm provided in the generic function needs to do something slightly different.

Friday, May 3, 2013

Generic functions: Restrictions

All generated versions of a generic function are meant to perform the same action. (only the data type may differ.) If you want to have different actions performed in different versions of a function, use overloading instead.

Friday, May 3, 2013