290 likes | 350 Views
Object Oriented Programming. Etgar 2008 Recitation 5. Function Pointers. A good tutorial is at http://www.newty.de/fpt/. Can We Increase Grades?. Assume we have a list of all student grades for the OOP course, and we would like to increase each and every one of them.
E N D
Object Oriented Programming Etgar 2008 Recitation 5 OOP Etgar 2008 – Recitation 5
Function Pointers A good tutorial is at http://www.newty.de/fpt/ OOP Etgar 2008 – Recitation 5
Can We Increase Grades? • Assume we have a list of all student grades for the OOP course, and we would like to increase each and every one of them. • The list is in the GradesList data structure that is accessed by GradesList::get(ID) and GradesList::set(ID, grade). • Calling get()/set() for each student is tedious. • How can we tell the GradesList to apply some function to each of its members? OOP Etgar 2008 – Recitation 5
The Solution • If GradesList had a function GradesList::ApplyToAll() we’d be done – but what if we don’t know in advance what function to apply? • A function pointer is what we need – a way to tell GradesList::ApplyToAll() which function to use. OOP Etgar 2008 – Recitation 5
Function Pointers – Possible? • We can think of a function name as a pointer to where its code begins. • Thus func is a memory address of where the code of func() begins. • But since a function has arguments and return value, the type of the pointer must specify them. OOP Etgar 2008 – Recitation 5
Function Pointers • A pointer to a function with no arguments and returning an int is declared as • int (*p)(); • Read it inside out – p is a pointer (the *) to a function (the right-hand ()) taking nothing (these parenthesis are empty) and returning an int. • The parenthesis around *p are needed to ensure that * is “applied” before (). OOP Etgar 2008 – Recitation 5
The Syntax • If idler() is defined as • int idler(); • we can write • p = idler; • p now points to the beginning of the code of idler(). • To run that code using p, type • (*p)(); • or in short • p(); OOP Etgar 2008 – Recitation 5
More Complex Syntax • The list of arguments is specified in the right-hand parenthesis. • If pow() is defined as • double pow(double b, double p); • the correct pointer is • double (*pow_p)(double, double); • The calling syntax is the same: • pow_p = pow; • pow_p(1.2, 2.3); OOP Etgar 2008 – Recitation 5
Typedef • Function pointer syntax is complex, especially when the function itself returns a function pointer. Use typedefs to simplify: • typedef double (*func_p)(double, double); • func_p is a type of a pointer to a function taking two doubles and returning an int. • Variable declaration now is more readable: • func_p p = pow; • p(1.2, 2.3); OOP Etgar 2008 – Recitation 5
Back to the Beginning • Now the grades can be increased: • int ten_percent(int grade) { • return grade*1.1; • } • void GradesList::ApplyToAll( int (*f)(int) ); • grades.ApplyToAll(ten_percent); OOP Etgar 2008 – Recitation 5
(Extremely) Complex Example • Define a variable of type “array of N pointers to functions returning pointers to functions returning pointers to char”. Huh? • The straightforward (and unreadable) solution: • char *(*(*a[N])())(); OOP Etgar 2008 – Recitation 5
Solution with Typedefs • typedef char *pc; /* pointer to char */ • typedef pc fpc(); /* function returning pointer to char */ • typedef fpc *pfpc; /* pointer to above */ • typedef pfpc fpfpc(); /* function returning... */ • typedef fpfpc *pfpfpc; /* pointer to... */ • pfpfpc a[N]; /* array of... */ • From “C FAQs” by Steve Summit. OOP Etgar 2008 – Recitation 5
Pointers to Members OOP Etgar 2008 – Recitation 5
Non-Static Member Functions • Just as we can declare a pointer to a function, we can declare a pointer to a non-static member function. • The syntax is different, since non-static member function takes an implicit this parameter. • The type of a pointer to non-static member function must include class specification, and the method invocation must be done on an object. OOP Etgar 2008 – Recitation 5
Example • struct C { • void func(); // (1) • void func() const; // (2) • void func(int); // (3) • }; • … • C temp; // temp is an object of class C • void (C::* p1)(); // pointers to members of C • void (C::* p2)() const; // … • void (C::* p3)(int); // … • p1 = C::func; • p2 = C::func; • p3 = C::func; • (temp.*p1)(); // invocation of (1) • (temp.*p2)(); // invocation of (2) • (temp.*p3)(3); // invocation of (3) OOP Etgar 2008 – Recitation 5
Notes • As always, typedefs will simplify reading: • typedef void (C::* Cptr)(); • Cptr cp = C::func; • Pointers to static member functions are regular function pointers. OOP Etgar 2008 – Recitation 5
Pointers to Data Members • Pointers to class data members should be specified with a class name. • struct C { • int i; • }; • … • C temp; // object of type C • int C::* p; // pointer to C's int data • // member • p = &C::i; // p points to i • cout << temp.*p; // prints temp.I OOP Etgar 2008 – Recitation 5
Templates Generic Programming OOP Etgar 2008 – Recitation 5
Why? • Often we meet algorithms, data structures or classes that are independent of the concrete type used in them. • QuickSort can sort anything (if it can be compared). • List can store anything. • But how can we write generic algorithms and data structures? OOP Etgar 2008 – Recitation 5
Bad Solutions • Using void* pointers: • Type-unsafe. • Error-prone. • Very unfriendly. • Deriving all classes from one superclass: • Type-unsafe. • Demands specific interface from all classes. • Both solutions disallow homogenous containers. OOP Etgar 2008 – Recitation 5
Templates • A template allows passing a type as a parameter to a class or a function. • This means that we can write classes and functions that are independent of the types they work with. • Actually, a template is a recipe for creating families of classes and functions. OOP Etgar 2008 – Recitation 5
Swap() • Consider the function swap() – the code is identical if it swaps two ints, two Rationals or two strings. • void swap(int& a, int& b) { • int temp = a; • a = b; • b = temp; • } OOP Etgar 2008 – Recitation 5
Function Templates • We can say that to the compiler by defining a function template: • template <typename T> • void swap(T& a, T& b) { • T temp = a; • a = b; • b = temp; • } • Within the template, T is another type, just like int or double. OOP Etgar 2008 – Recitation 5
Template Instantiation • The compiler will use this template to instantiateswap() for types it needs: • When it needs to swap ints, it will generate a version for ints. • If it needs to swap strings, it will generate a new version for strings. • The versions it generates will have no connection to one another (apart from similar name). OOP Etgar 2008 – Recitation 5
Lack of Conversions • The compiler decides which version to instantiate based on the parameters types. • This is called template argument deduction. • Conversions are not considered for this. • I.e., these calls will not compile: • int i; short s; double d; • swap(i, d); // no version for int and a double • swap(i, s); // no version for int and a short • The only conversions used are • conversion to const pointer or reference, • array and function to pointer. OOP Etgar 2008 – Recitation 5
Class Templates • What about classes? Obviously, the code for ListOComplex will work for Rationals, ints or strings, if we didn’t hardwire the type into it. • We can define a class template for a List, and List users will specify the concrete type when creating List objects. • The compiler will create instantiated classes as needed. OOP Etgar 2008 – Recitation 5
Class List • template <typename T> • class List { • public: • List(const List&); • bool push_front(const T&); • T pop_front(); • … • }; • Within List’s methods, T is another type, just like int or double. OOP Etgar 2008 – Recitation 5
Instantiated Classes • With class templates we need to specify the type parameter to create an object: • List<Complex> listOcomplex; • List<int> listOint; • The compiler creates an instance of class List for Complexes and an instance for ints. • They have nothing to do with one another. • Note that copy c’tor in List has a parameter of type List, not List<T>. • Both forms can be used – but the former only within the template itself. OOP Etgar 2008 – Recitation 5
Notes • Templates can be complicated: • Referring to base class template from within a derived class template requires the use of this->, using or ::. • Care should be taken for templates within templates – the >> in List<vector<int>> is interpreted as operator>>(). • But templates allow generic programming. • In fact, templates themselves form a complete programming language. OOP Etgar 2008 – Recitation 5