object oriented programming elhanan borenstein [email protected] lecture #10 copyrights © elhanan...
TRANSCRIPT
Object OrientedProgramming
Elhanan Borenstein
Lecture #10
copyrights © Elhanan Borenstein
Agenda Templates:
Template Functions
Template Classes
Inheriting Template Classes
copyrights © Elhanan Borenstein
Template Functions
copyrights © Elhanan Borenstein
Template Functions
We already saw several mechanisms that can support having similar “functions” for handling various types: (Polymorphism …) (Macros and) Functions overloading
Macros: #define SWAP(a,b) … Using function overloading we can implement several
functions with the same name that differ only in the parameter’s type. For example : Swap()
Motivation
copyrights © Elhanan Borenstein
void Swap(int& a, int& b) { int temp = a; a = b; b = temp;}
void Swap(float& a, float& b) { float temp = a; a = b; b = temp;}
void Swap(char*& a, char*& b) { char* temp = a; a = b; b = temp;}
Template Functions
It would be very beneficial if we could implement only one function which will describe the Swap() function (which is similar to all types) and still work for every type.
Using Template Functions we can do just that… Example: tempfunc.cpp
The line “template<class T>” informs the compiler that this is a template functions, including a general type T, and that it should “unfold” the function according to the various options, T will receive.
Introduction
copyrights © Elhanan Borenstein
template<class T> void Swap(T& a, T& b) { T temp = a; a = b; b = temp;}
void main(){ int i=4, j=9; Swap(i, j);
char* str1 = “hello”; char* str2 = “world”; Swap(str1, str2);}
Template Functions
A template function actually represents a collections of functions. For each (different) usage (activation of the function with a different type) of the function:
the compiler will first create the appropriate copy of the function … and then compile that copy
Will that code work?
How Does it work?
copyrights © Elhanan Borenstein
template<class T> void DoSomething( int I ) { T a, b; b = a = i;}
Template Functions
The template function must be included (directly or through #include) in the file that makes use of it – (WHY?)
Guidelines
copyrights © Elhanan Borenstein
template<class T> void Swap(T& a, T& b) …
void main() { Swap(i, j);…
a.cpp b.cpp
template<class T> void Swap(T& a, T& b) …
template<class T> void Swap(T& a, T& b)void main() { Swap(i, j);…
a.cpp b.cpp
template<class T> void Swap(T& a, T& b) …
#include “a.h”void main() { Swap(i, j);…
a.h b.cpp
Template Functions
More than one general type can be defined. For example: template<class key, class value>
Using the name T, is of course optional Instead of <class T> we can also use <typename T> For each “class T”, only one type can be used when calling the function no casting
Format
copyrights © Elhanan Borenstein
Template Functions
A template function may pose restrictions upon the types of the parameters that can actually be send, according to the use of this parameters within the function.
(The template function documentation should specify these restrictions !)
What restrictions are posed on T in this function? Specialization: Example: spec.cpp
Restrictions and Specialization
copyrights © Elhanan Borenstein
template<class T> void PrintIfEqual(T& a, T& b) { if (a == b)
cout<<a<<“ and “<<b<<“ are equal.”<<endl;}
Template Functions
Template functions can be used to implement Generic Algorithms (as we did with Polymorphism).
The Generic Algorithm in the function will include calls to helper functions which will be activated according to the type of the operating object. When the function gets an object of a certain type, we can be sure that the function of that specific type will be activated. (WHY?) No need for inheritance of virtual functions.
Reminder: how did we implement this GA with Polymorphism? So…is there really no need for inheritance of polymorphism???
Generic Algorithms with Template Functions
copyrights © Elhanan Borenstein
template<class T> double Calc3DVolume(const T& shape) { return shape.CalcBase() * shape.GetHeight();}
STL
Template Functions
The Rule of Thumb (as always – a Logical Argument): If the algorithm is truly general, and can be used for several
“families” (e.g. Max, Swap) Use Template Function If the algorithm is general only within a certain family (base class
and derived classes) Use Polymorphism
Template Functions vs. Polymorphism
copyrights © Elhanan Borenstein
Polymorphism Template Functions
Code Size - The GA exists once (in the base class)- No code inflating
- The GA is duplicated for every type used- Code Inflating
Runtime - Dynamic function binding- Slower
- Static function binding- Faster
Usage - GA serves all Derived class- No need to implement all helper functions- Requires a well planned inheritance hierarchy
- GA serves any type that support the helper functions.- No need for inheritance (not always good)
Template Classes
copyrights © Elhanan Borenstein
Template Classes
In the same manner we used Template Functions we can use Template Classes: Template Function – Defines a collection of functions that differ in the type of the parameters. Template Class – Defines a collection of classes the differs in the type being used.
Example array.cpp
Introduction
copyrights © Elhanan Borenstein
Template Classes
template<class T> class Array { … }; The name of the class is Array<…> (and not just Array)
When creating an object of a template class, the type we wish to use should be passed as a parameter to the template (array<int>). When calling a template function, the type should not be specified: the function will identify the type through to the function parameters.
The line “template<class T>” before the class definition, informs the compiler that the class include a general type that should be unfolded according to the class actual usage.
When a method is implemented externally, the template usage should be specified again – the function will be unfolded for each class created. Will the Print() function be using the template type???
Principles
copyrights © Elhanan Borenstein
Template Classes
To create an actual object according to the template class:
TemplateClass<T_Real_Type> ObjName(c’tor_params); The guidelines we saw in template functions still apply:
The template class must be included in the file that uses it. For each “class T”, only one type can be used when calling the function no casting More than one general type can be defined. For example: template<class T, class G>
Guidelines
copyrights © Elhanan Borenstein
Template Classes
Template parameters can also be non-type constants !!! (that’s why the word “class” can not be dropped) example: const_array.cpp
Template parameters can have default values !!! template<class T = int, int S = 40> Not fully supported… meaningless in template function…
Guidelines – cont’
copyrights © Elhanan Borenstein
Template Classes
Main usage of Template Classes: General Data Structures Template classes can be used to implemented General Containers. A very common usage (STL). So… when will we use Polymorphism
Smart Solution: Combination !!!!
Template Classes vs. Polymorphism
copyrights © Elhanan Borenstein
Polymorphism Template Functions
Code Size - The container exists once (in the base class)- No code inflating
- The container is duplicated for every type used- Code Inflating
Runtime - Dynamic function binding- Slower
- Static function binding- Faster
Flexibility - Container can store various derived objects simultaneously
- Each container can store only objects of same type
Inheriting Template Classes
copyrights © Elhanan Borenstein
Inheriting Template Classes
Template classes can be inherited according to the standard inheritance guidelines. Inheritance can use two approaches (both very common):
The derived class is not a template. The actual type will be defined when inheriting.
class ExtendedIntArray : public Array<int> The derived class is by itself a template class. No need to specify the type when inheriting.
template<class T>class ExtendedArray : public Array<T>
Introduction
copyrights © Elhanan Borenstein
Inheriting Template Classes
If while inheriting the template class, we specify all the parameters of the template class, we will actually create a new regular (non-template) class.
Example: ExtendedIntArray
A Class Derived from Template Class
copyrights © Elhanan Borenstein
Inheriting Template Classes
Example: extintarray.cpp Example: temptemp.cpp
A Template Class Derived from Template Class
copyrights © Elhanan Borenstein
I'm class A<int>I hold intThe inner value is: 9
I'm class B<class A<int> >I hold class A<int>The inner value is: I'm class A<int>I hold intThe inner value is: 9
I'm class A<int>I hold intThe inner value is: 9
What if Print() wasn’t virtual?
What if we would use Print without overloading << ?
Exercises…
copyrights © Elhanan Borenstein
Exercise 1 Implement a generic Find() function, which gets:
a pointer to the beginning of an array a pointer to the end of an array the value to search for
The function returns the address of the first items in the array that is equal to the given value or the address of one location after the last item if the value was not found.
copyrights © Elhanan Borenstein
template<class T>T* Find(T* begin, T* end, T value){ while (begin != end) if (*begin == value)
return begin; else
begin++;
return begin;}
void main(){ int array[ ] = {3,2,5,7,2,8,11}; int* j = Find (array, array + 6, 7);
}
Exercise 2.1 Implement a class called Sqr which will include only one thing:
an overloading of the operator () which will get as a parameter T& and will assign to it its square value.
copyrights © Elhanan Borenstein
class Sqr{public: template<class T> void operator() (T& t) {
t = t*t; }};
void main(){ Sqr MySqrMachine;
int i = 2; float f = 3.25; MySqrMachine(i); MySqrMachine(f);}
Exercise 2.2 Implement a general DoIt fucntion which gets:
a pointer to the beginning of an array a pointer to the end of an array A reference to an object
The function should go over all elements of the array and send each element to the () operator if the object it got.
copyrights © Elhanan Borenstein
template<class T, class G>void DoIt(T* begin, T* end, G& Obj){ while (begin != end) { obj(*begin); begin++; }}
Exercise 2.all Putting it all together…
copyrights © Elhanan Borenstein
class Sqr{public: template<class T> void operator() (T& t) {
t = t*t; }};
void main(){ int array[ ] = {1,5,7,8,3,2,9,2,12};
DoIt(array, array + 8, Sqr());
}
template<class T, class G>void DoIt(T* begin, T* end, G& Obj){ while (begin != end) { obj(*begin); begin++; }}
AMAZING !!!! DoIt() is completely general:
It doesn’t know the array type.
It doesn’t know the action it is doing
Food for Thoughts Imagine a template class
We wish that all instances of MyClass will be friends... friend MyClass<T> ??? friend MyClass<G> ???(and than template<class T, class G>)
What is a regular (non-template) class A wishes to give friendship to all instances of MyClass? What’s the meaning of all that???
copyrights © Elhanan Borenstein
template <class T>class MyClass{ T t; …};
Questions?
copyrights © Elhanan Borenstein