an introduction to c++ lecture 08: abstractionekp · abstraction this procedure is called...
TRANSCRIPT
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
INSTITUTE OF EXPERIMENTAL PARTICLE PHYSICS (IEKP) – PHYSICS FACULTY
An Introduction to C++
Lecture 08: Abstraction
Roger Wolf18. Mai 2018
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
INSTITUTE OF EXPERIMENTAL PARTICLE PHYSICS (IEKP) – PHYSICS FACULTY
Part 1:
Abstraction
1/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
The case of abstraction
● Imagine you have a program to manage bank accounts. This program has two classes Savings and Checking, which differ in the way withdrawals are charged.
● The two classes have the following structure:
Checking
withdrawal()
deposit()
accountNo()
accountNo_balance_
Savings
withdrawal()
deposit()
accountNo()
accountNo_balance_noWithdrawals_
The first 10 withdrawals are for free (requires one additional member)
Withdrawals are higher charged if the balance falls below 100$
2/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Savings
withdrawal()
deposit()
accountNo()
accountNo_balance_noWithdrawals_
The case of abstraction
● The two classes have the following structure:
● How can the redundancy in the defini-tion of these two classes be removed?
The first 10 withdrawals are for free (requires one additional member)
Checking
withdrawal()
deposit()
accountNo()
accountNo_balance_
● Imagine you have a program to manage bank accounts. This program has two classes Savings and Checking, which differ in the way withdrawals are charged.
2/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Solution-1
● Let Savings inherit from Checking, add the additional member, and overload withdrawal().
● The two classes have the following structure:
Savings
withdrawal() noWithdrawals_IS_A
inherits from
Checking
withdrawal()
deposit()
accountNo()
accountNo_balance_
3/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Solution-1
● The two classes have the following structure:
Why Solution-1 is suboptimal:
● A savings account is not a checking account. The class structure does not reflect reality.
● This can lead to misunderstandings and errors.
● Savings depends on Checking. What if Checking changes one day?
Savings
withdrawal() noWithdrawals_
Checking
withdrawal()
deposit()
accountNo()
accountNo_balance_
● Let Savings inherit from Checking, add the additional member, and overload withdrawal().
3/32
IS_A
inherits from
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Solution-2
● Savings and Checking both describe accounts: introduce Account as a common base class.
Account
withdrawal()
deposit()
accountNo()
accountNo_balance_
Savings
withdrawal() noWithdrawals_
inherits from
Checking
withdrawal()
IS_AIS_Ainherits from
● Both derived classes overload withdrawal() corresponding to their attributes.
4/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Abstraction
● This procedure is called abstraction.
● It follows our natural intuition: try to identify what certain groups of objects have in common. Subsume it into a common base class.
● Such abstraction hierarchies have no unique solution. Depending on the use case and level of required knowledge this can lead different answers.
● Identifying the proper abstraction model for your problem might well happen in an iterative procedure as described in Lecture05.
4/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Problem with Solution-2
● What should be the implementation of Account::withdrawal()?
● Account is an abstraction of Checking and Savings. It cannot be made concrete (see slide 7).
5/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Problem with Solution-2
● What should be the implementation of Account::withdrawal()?
● Another example from nature: tigers, apes and giraffes are mammals → but you wont find an animal on earth that is just a mammal.
5/32
● Account is an abstraction of Checking and Savings. It cannot be made concrete (see slide 7).
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
The abstract base class
● The C++ solution to this problem is to provide explicitly NO implementation for withdrawal() in the base class.
● Account is then called abstract
6/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
The abstract base class
This indicates that withdrawal() will not have an implementation in Account
● The C++ solution to this problem is to provide explicitly NO implementation for withdrawal() in the base class.
● Account is then called abstract
6/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
The abstract base class
This indicates that withdrawal() will not have an implementation in Account
A possible implementation in Savings
● The C++ solution to this problem is to provide explicitly NO implementation for withdrawal() in the base class.
● Account is then called abstract
6/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
● The C++ solution to this problem is to provide explicitly NO implementation for withdrawal() in the base class.
● Account is then called abstract
The abstract base class
This indicates that withdrawal() will not have an implementation in Account
A possible implementation in Savings
A possible implementation in Checking
6/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Object declaration
● No objects can be instantiated from Account (after all its implementation is incomplete):
● To make a concrete class, all member functions (e.g. of Account) have to be implemented (=overloaded) in derived classes. Implementing only a fraction can be done to create another abstract base class.
7/32 Back to slide 5
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Abstract classes as arguments
● No problem, as long as the passed arguments are concrete classes. This is automatically the case if you pass objects.
8/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Abstract classes as arguments
● No problem, as long as the passed arguments are concrete classes. This is automatically the case if you pass objects.
No problem as long as a concrete derived class is passed
8/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Why declare Account::withdrawal() at all?
● If withdrawal() has a real implementation only in Savings and Checking, why do I need to have a declaration of this function in Account at all?
Imagine withdrawal() were not declared:
● What function should be called? Account has no function withdrawal().
● How should C++ know how to overload it in the context of polymorphism?
9/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
What are abstract classes good for?
● They allow you to reduce redundancies.
● They minimize your work in debugging and code maintenance.
● They allow to write code that is closer to reality/daily life experience.
● They allow to use polymorphism:E.g. we could have implemented withdrawal() in each derived class w/o polymorphism:
10/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
What are abstract classes good for?
● They allow you to reduce redundancies.
● They minimize your work in debugging and code maintenance.
● They allow to write code that is closer to reality/daily life experience.
● They allow to use polymorphism:E.g. we could have implemented withdrawal() in each derived class w/o polymorphism:
replace by...
10/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
What are abstract classes good for?
● They allow you to reduce redundancies.
● They minimize your work in debugging and code maintenance.
● They allow to write code that is closer to reality/daily life experience.
● They allow to use polymorphism:E.g. we could have implemented withdrawal() in each derived class w/o polymorphism:
replace by...
Note: not only that overloading of fn() is required. The use of fn() also requires more knowledge of Savings and Checking. Together with less intuitive use → doubly error prone!
10/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
A new type of interface
● You can also use abstract classes to define interfaces for code developers. Imagine the following scenario:
ObjectCreator
virtual readFrom()=0
virtual writeTo()=0
virtual create()=0
used in… Application● Provides a container with basic objects.● ObjectCreator has read/write access to
this container to write more complex objects composed of the basic objects into it.
ToyCreatorPatternCreator
PairCreatorXXCreator
…
Der
ived
con
cret
e cl
asse
sIn
terf
ace
to A
pplic
atio
n fo
r th
e de
velo
per
11/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Run time type identification (RTTI)
● Sometimes you might want to know the runtime type of an object in a function. This can be obtained from dynamic downcasts.
12/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Run time type identification (RTTI)
● Sometimes you might want to know the runtime type of an object in a function. This can be obtained from dynamic downcasts.
● You can apply dynamic downcasts, which are evaluated at runtime on pointers or references.
● For references they throw exceptions, e.g. if acc does not have the runtime type Savings.
● For pointers it returns a NULL pointer.
12/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Run time type identification (RTTI)
● This functionality is controversial: it foils the idea of object oriented programming, e.g. fn(Account* ) pretends that you only need to know something about Account, but inside more knowledge about Savings is also required.
● If used extensively it points to procedural programming in an object oriented language/disguise.
● If you encounter this use case try to think of a better maintainable solution.
13/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
How to prevent RTTI
● Add an abstract member function noWithdrawals() to Account.
● Overload it in Savings with a corresponding function that returns the value.
● Overload it in Checking with an empty function.
14/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
INSTITUTE OF EXPERIMENTAL PARTICLE PHYSICS (IEKP) – PHYSICS FACULTY
Part 2:
Multiple inheritance
15/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Multiple inheritance
● Sometimes your class inherits attributes from more than one abstract instance. Imagine an AmphibianVehicle, which inherits from Boat and Car.
Boat
motor
propeller
hull
Car
motor
wheels
indicators
AmphibianVehicle
motor
propeller
hull
motor
wheels
indicators
16/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Multiple inheritance
● Sometimes your class inherits attributes from more than one abstract instance. Imagine an AmphibianVehicle, which inherits from Boat and Car.
Inheritance from two base classes
17/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Ambiguities due to inheritance
● As shown in the following example multiple inheritance can lead to ambiguities:
What class do we refer to here?
18/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Ambiguities due to inheritance
● As shown in the following example multiple inheritance can lead to ambiguities:
What class do we refer to here?
This can formally be resolved by identifying the class by namespace
18/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Another case of abstraction
● This solution is still unsatisfactory, as long our AmphibianVehicle has only one motor. In this case our problem originates from an improper abstraction. What we want looks more like this:
Boat
motor
propeller
...
EDVehicle
motor
Car
motor
wheels
...
AmphibianVehicle
motor
...
19/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Another case of abstraction
● This solution is still unsatisfactory, as long our AmphibianVehicle has only one motor. In this case our problem originates from an improper abstraction. What we want looks more like this:
Boat
motor
propeller
...
EDVehicle
motor
Car
motor
wheels
...
AmphibianVehicle
motor
...
20/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Another case of abstraction
● This solution is still unsatisfactory, as long our AmphibianVehicle has only one motor. In this case our problem originates from an improper abstraction. What we want looks more like this:
Boat
motor
propeller
...
EDVehicle
motor
Car
motor
wheels
...
AmphibianVehicle
motor
...
21/32
Executable for testing...
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Another case of abstraction
● This solution is still unsatisfactory, as long our AmphibianVehicle has only one motor. In this case our problem originates from an improper abstraction. What we want looks more like this:
Boat
motor
propeller
...
EDVehicle
motor
Car
motor
wheels
...
AmphibianVehicle
motor
...
21/32
Executable for testing...
● If you try to compile this it wont work either: even if you explicitly cast AmphibianVehicle to EDVehicle the compiler will complain that it cannot resolve which motor you are talking about.
● The reason lies in the way the memory block is filled (see slide 22)
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
What hast thou done?
EDVehicle
Boat
EDVehicle
Car
Am
phib
ianV
ehic
le
● The result of our implementation:
How an AmphibianVehicle looks like in the memory block
22/32 Back to slide 21
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
What hast thou done?
EDVehicle
Boat
EDVehicle
Car
Am
phib
ianV
ehic
le
Boat
motor
propeller
...
EDVehicle
motor
Car
motor
wheels
...
AmphibianVehicle
motor
...
EDVehicle
motor
● The result of our implementation:
How an AmphibianVehicle looks like in the memory block
22/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Virtual inheritance
● We can still achieve what we want by virtual inheritance:
23/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Virtual inheritance
● We can still achieve what we want by virtual inheritance:
Results in the intended inheritance structure…
23/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Virtual inheritance
● We can still achieve what we want by virtual inheritance:
Results in the intended inheritance structure…
23/32
Everything fine here
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Virtual inheritance
● We can still achieve what we want by virtual inheritance:
Results in the intended inheritance structure…
23/32
Everything fine here
EDVehicle
Boat
Car
Am
phib
ianV
ehic
le
How an AmphibianVehicle looks like in the memory block
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
INSTITUTE OF EXPERIMENTAL PARTICLE PHYSICS (IEKP) – PHYSICS FACULTY
Part 3:
Templating
24/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-1: function overloading
25/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-1: function overloading
● This solution is not very satisfactory since you have to implement the function over and over again.
25/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-2: template functions
● The same can be achieved via a template function.
26/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-2: template functions
● The same can be achieved via a template function.
Keyword
26/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-2: template functions
● The same can be achieved via a template function.
Keyword Class type
26/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-2: template functions
● The same can be achieved via a template function.
Keyword Class type
T is used as a variable throughout the function declaration part
26/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-2: template functions
● The same can be achieved via a template function.
Keyword Class type
T is used as a variable throughout the function declaration part
● A more complex example:
27/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template functions
● Take a function max(a,b) that is supposed to return the larger of two values. Imagine you would like to use it equally well for int, float, double, …
Solution-2: template functions
● The same can be achieved via a template function.
Keyword Class type
T is used as a variable throughout the function declaration part
● A more complex example:
● <…> can have more argu-ments.
● All arguments in <…> must be used in the following declaration.
27/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
General remarks
● A function template does not become a C++ function before your fully specify it (=fully expand its template arguments).
● For full expansion a reference to the function is sufficient.
● Consequently you can write as many template functions as you want into your source code. They will not use any memory in your executable until expanded. Each fully specialized version will use its own memory in the executable though, i.e. int max(int, int) takes its own space as well as float max(float, float), aso …
● Consequently you can even write code with syntax errors. Since C++ will compile it only when fully expanded somewhere in your code, your code would compile without complaints unless you do expand somewhere.
28/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Potential ambiguities
● There may be danger of confusion. See the following example:
29/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
● There may be danger of confusion. See the following example:
What function will be called here?
29/32
Potential ambiguities
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
● There may be danger of confusion. See the following example:
What function will be called here?
To resolve this kind of confusion the following ordering applies:● Search for an explicit function that fits to
the arguments.● Search for a function template that can fit
the arguments when expanded properly.● Search for an explicit function that can fit
if one or more arguments are converted.
29/32
Potential ambiguities
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template classes
● The concept of template functions can be extended to classes. Check the following example to see how this works:
30/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template classes
● The concept of template functions can be extended to classes. Check the following example to see how this works:
Keyword and template arguments
30/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template classes
● The concept of template functions can be extended to classes. Check the following example to see how this works:
Keyword and template arguments
Declaration of a pointer of type T
30/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template classes
● The concept of template functions can be extended to classes. Check the following example to see how this works:
Keyword and template arguments
Declaration of a pointer of type T
30/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template classes
● The concept of template functions can be extended to classes. Check the following example to see how this works:
Keyword and template arguments
Declaration of a pointer of type T
Function definition outside the class declaration
30/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Template classes
● The concept of template functions can be extended to classes. Check the following example to see how this works:
30/32
Example of usage
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Final remarks
● The most obvious use case for templates in C++ programming are container classes, as introduced in Lecture03, e.g. std::vector<T>.
31/32
Priv. Doz. Dr. Roger Wolf http://ekpwww.physik.unikarlsruhe.de/~rwolf/
Summary
● Abstraction.
● The abstract base class.
● Run time type identification (RTTI).
● Multiple inheritance.
● Virtual inheritance.
● Template functions.
● Template classes.
32/32