Function Overloading Templated Functions Templated Classes Pointers to

  • Slides: 29
Download presentation
Function Overloading, Templated Functions, Templated Classes, Pointers to Functions Horton pp. 247 – 254

Function Overloading, Templated Functions, Templated Classes, Pointers to Functions Horton pp. 247 – 254 (function overloading and templated functions) Tapestry Sect. 11. 2 (for templated functions) Horton pp. 378 – 412 (templated classes with some advanced issues that we will not see) Tapestry Section 12. 3. 6 (templated classes – more condensed) Horton pp. 231 – 237 (Pointers to Functions) Functors (Function Objects) are at the end of these slides, but we will skip them (not responsible) 1

Aim Sometimes you need variations of the same basic function: – one function to

Aim Sometimes you need variations of the same basic function: – one function to sort an array of integers and another one to sort an array of characters – one function to swap two variables of type int, another one to swap two variables of type char – one function to find the maximum element of an array of ints, another one for an array of strings –. . . You can: 1. define two different functions with the same name but taking different types of arguments: function overloading 2. use a templated function which uses a templated type 2

Function overloading Define two different functions that take the appropriate parameter types: void Sort

Function overloading Define two different functions that take the appropriate parameter types: void Sort (vector<int> & a) {. . . } void Sort (int a[], int size) {. . . } void Sort (vector<string> & a) {. . . } void Sort (string a[], int size) {. . . } 3

Function overloading Define: void Sort (vector<int> & a) {. . . } void Sort

Function overloading Define: void Sort (vector<int> & a) {. . . } void Sort (vector<string> & a) {. . . } The appropriate function will be called depending on the parameter. E. g. vector <int> nums; vector <string> names; sort(nums); //calls the first function sort(names); //calls the second function This may be the right solution in some cases. But function overloading duplicates code: – maintaining is difficult (different versions of a sort function); if there is a change, you have to update all 4

Function overloading Also, you cannot do this with function overloading: int Find. Roots(double a,

Function overloading Also, you cannot do this with function overloading: int Find. Roots(double a, double b, double c) double Find. Roots(double a, double b, double c) Why? • Because from the types of the parameters passed, you cannot determine which function should be called • The signatures (parameters+function name) of two different functions should not be completely the same • You cannot differentiate between two functions just using their return type 5

Templated functions writing a single instance of a function with generic type name simple

Templated functions writing a single instance of a function with generic type name simple form for ints: void Swap(int & a, int & b) { int temp; template <class Type> void Swap(Type & a, Type & b) { Type temp; temp = a; a = b; b = temp; } Any name can be the template parameter (e. g. Type, my. Type, sablon. Tipi, . . . ) Templated type is not actually known until the function is called. 6

template <class Type> void Swap(Type & a, Type & b) { Type temp; temp

template <class Type> void Swap(Type & a, Type & b) { Type temp; temp = a; a = b; b = temp; void Swap(double& a, double& b) { double temp; temp = a; a = b; b = temp; } } int main() { double d 1, d 2; cin >> d 1 >> d 2; Swap (d 1, d 2); string s 1, s 2; cin >> s 1 >> s 2; Swap (s 1, s 2); void Swap(string& a, string& b) { string temp; temp = a; a = b; b = temp; } Not explicitly written but compiled in this way Templated functions return 0; } Calling the function actually determines what Type is at compile-time. 7

Templated functions: more complex How can we swap the values at the given locations

Templated functions: more complex How can we swap the values at the given locations of a vector of any type? template <class T> void Swap(vector<T> & list, int i, int j) { T temp; temp = list[i]; list[i] = list[j]; list[j] = temp; } You may have a local variable of a templated type, but you should have at least one parameter of the same template type. In short, everywhere you had a element type (e. g. int), you put a new templated type name (e. g. T), and add template <class typename> at the beginning of the function. 8

Templated functions: more complex template <class Type> void Print(const vector<Type> & list) { int

Templated functions: more complex template <class Type> void Print(const vector<Type> & list) { int i, count; count = list. Size(); for (i=0; i < count; i++){ cout << list[i] << endl; } } 9

Templated functions: more uses and rules template <class T> T Do. Stuff(T myvar) //template

Templated functions: more uses and rules template <class T> T Do. Stuff(T myvar) //template types can be return type, but there must be at least //one parameter of template type template <class T> T do. This (int x) //this is not valid template <class no. Name> no. Name Find. Last. Element(vector<no. Name> & list 1) //this is valid template <class T 1, class T 2> int Compare. Lists(vector<T 1> & list 1, vector<T 2> & list 2) //note that we have two templated types (T 1 and T 2) //in general you can have as many templated types as you need //but you have to use all of them in the parameter list 10

function overload vs templated functions: comparison (Tapestry pp 543) Function overloading duplicates code: –

function overload vs templated functions: comparison (Tapestry pp 543) Function overloading duplicates code: – maintaining is difficult (multiple versions of a function that does the same job for different parameter types) – each must be changed if there is a need Function templates: – reuses code, rather than to duplicate it – causes code bloat: each instantiation of a function (i. e. each call to the function using a different type) adds new object code: that is why it is called template You should also consider reusing simple functions with type casting as a 3 rd alternative, (when suitable) since in this case there is neither code duplication NOR code bloat! – Define: void Swap (double & a, double & b ) – Use with ints as: int a, b; Swap( (double)a, (double)b ); You can use this option when the task is suitable and –of course– types are easily convertible!

Templated Classes 12

Templated Classes 12

Templated Classes Similar to the idea of a templated function, you can have templated

Templated Classes Similar to the idea of a templated function, you can have templated classes. Main idea: – types are not fixed at class declaration and definition; they are instantiated when the objects are created. Similar to templated functions, these provide type flexibility in class definitions. For instance, our linked list class contains ints in node. For nodes with strings, you need another class. This increases the size of the code. With the use of templated classes, we define the class and its implementation once and be able to be use it for integers or strings, etc. – e. g. Standart vector class is a templated class vector<int> myintarr(1000); vector<string> mystrarr(1000); 13

Templated Classes It is a good idea to develop a non-templated version first, and

Templated Classes It is a good idea to develop a non-templated version first, and then convert to a templated class later. Such a conversion is mostly changing the syntax of declarations and function/class headings by applying some simple rules. We will convert our previously developed Linked. List class with integer container to a templated class. But before that I will give a smaller example Normally what you have to do are as follows. 1. add template <class item. Type> before the class heading and before each member function implementation (not declaration). Here item. Type is the element type that you store in a node. 2. replace each of the occurrence of the element type with item. Type everywhere in the class declaration (linkedlist. h file) and class implementation (linkedlist. cpp file). 3. add <item. Type> after the class name (in our case after Linked. List) in the class implementation file (linkedlist. cpp) – There is an exception for this rule for the constructors/destructor. See the example codes in the coming slides. 14

Templated Classes This procedure works fine if you do not use another templated class

Templated Classes This procedure works fine if you do not use another templated class or templated struct in your class. If you define your struct within the class (as in the case of Link. String. Set class), again this procedure works. However, if you declare another templated class or a templated struct (in our case struct node) before your class, but want to use them in your class, you have to refer to these other structs/classes by adding <item. Type> after the struct/class names everywhere (in both. h and. cpp files of your class). – This is the case in our Linked. List example Structs can also be templated like classes (the rules are the same) 15

Templated Classes – Small Example A class for Addition. – Two private data members

Templated Classes – Small Example A class for Addition. – Two private data members are added using + operator. Private data members are templates template <class Op. Type> class Add { public: Add (Op. Type op 1, Op. Type op 2); Op. Type operand (int i); Op. Type result (); private: Op. Type my. Op 1, my. Op 2; }; int main() { Add<int> a(5, 12); cout << a. operand(1) << " + " << a. operand(2) << " = " << a. result() << endl; Add<string> b("cs", "204"); cout << b. operand(1) << " + " << b. operand(2) << " = " << b. result() << endl; Add<char> c('2', '3'); cout << c. operand(1) << " + " << c. operand(2) << " = " << c. result() << endl; template <class Op. Type> Add<Op. Type>: : Add (Op. Type a, Op. Type b) return 0; : my. Op 1(a), my. Op 2(b) {} } template <class Op. Type> Op. Type Add<Op. Type>: : operand (int i) { if (i==1) return my. Op 1; else if (i==2) return my. Op 2; } template <class Op. Type> Op. Type Add<Op. Type>: : result () { return my. Op 1 + my. Op 2; } In main, class is instantiated using three different types for Op. Type: int, string, char. What is output? See 5 + 12 = 17 addtemplate. cpp cs + 204 = cs 204 2 + 3 = e 16

Templated Classes – Linked. List class • First we need to convert the node

Templated Classes – Linked. List class • First we need to convert the node struct to template <class item. Type> struct node { item. Type info; node *next; node () {} node (const item. Type & s, node * link) : info(s), next (link) {} }; 17

Templated Classes – Linked. List class • Then the class definition is converted (Linked.

Templated Classes – Linked. List class • Then the class definition is converted (Linked. List. Template. h) template <class item. Type> class Linked. List { private: node<item. Type> * head; int size; public: Linked. List (); Linked. List (const Linked. List &); ~Linked. List (); void print. List() const; void add. To. Beginning(item. Type n); void delete. List (); const Linked. List & operator = (const Linked. List & rhs); node<item. Type> * create. Clone () const; }; 18

Templated Classes – Linked. List class • • After that member functions are converted

Templated Classes – Linked. List class • • After that member functions are converted (Linked. List. Template. cpp) Some examples here (see Linked. List. Template. cpp for all) //copy constructor template <class item. Type> Linked. List<item. Type>: : Linked. List (const Linked. List<item. Type> & copy) { head = copy. create. Clone(); //constructor size = copy. size; template <class item. Type> } Linked. List<item. Type>: : Linked. List () { //destructor head = NULL; template <class item. Type> size = 0; Linked. List<item. Type>: : ~Linked. List () } { node<item. Type> * ptr = head; while (ptr != NULL) { node<item. Type> * temp = ptr->next; delete ptr; ptr = temp; } } 19

Templated Classes – Linked. List class template <class item. Type> void Linked. List<item. Type>:

Templated Classes – Linked. List class template <class item. Type> void Linked. List<item. Type>: : add. To. Beginning (item. Type n) { node<item. Type> *ptr = new node<item. Type>(n, head); head = ptr; size++; } template <class item. Type> const Linked. List<item. Type> & Linked. List<item. Type>: : operator = (const Linked. List<item. Type> & rhs) { if (this != &rhs) { delete. List(); head = rhs. create. Clone(); size = rhs. size; } return *this; } 20

Templated Classes – Linked. List class template <class item. Type> node<item. Type> * Linked.

Templated Classes – Linked. List class template <class item. Type> node<item. Type> * Linked. List<item. Type>: : create. Clone () const { if (head == NULL) return NULL; node<item. Type> * head. Clone = new node<item. Type> (head->info, NULL); node<item. Type> * ptr = head->next; //second node in orig. node<item. Type> * ptr. Clone = head. Clone; //to track the clone list while (ptr != NULL) { ptr. Clone->next = new node<item. Type> (ptr->info, NULL); ptr = ptr->next; ptr. Clone = ptr. Clone->next; } return head. Clone; } 21

Templated Classes – Linked. List class Using in main int main() { string baskan[]

Templated Classes – Linked. List class Using in main int main() { string baskan[] = {"Ahmet Agaoglu", "Ali Koc", "Mustafa Cengiz", “Ahmet Nur Cebi"}; Linked. List<string> strlist; //Linked list object with string element type Linked. List<int> intlist; //Linked list object with integer element type for (int k=0; k < 4; k++) { strlist. add. To. Beginning(baskan[k]); intlist. add. To. Beginning(k+1); } cout << "string list contains: n"; strlist. print. List(); cout << "integer list contains: n"; intlist. print. List(); See linkedlisttemplate. h, linkedlisttemplate. cpp and linkedlisttemplatedemo. cpp } 22

Templated Classes – Link. String. Set class See Tapestry pp. 625 – 631 for

Templated Classes – Link. String. Set class See Tapestry pp. 625 – 631 for the templated version of Link. String. Set class. Tapestry renamed templated version of this class as Link. Set Conversion to template is not different than what we have done for our Linked. List class, but in Link. Set class the Node struct definition is in the class definition. Thus Node struct is not templated and referral to node does not require to add <item. Type> to the end. However, you have to refer to Node outside of the class definition by putting typename Link. Set<item. Type>: : before Node The use of typename keyword is not mentioned in Tapestry, but it is needed in Visual Studio 2012 (also in some earlier versions of VS). 23

Fundemental Dilemma in using Templated Classes (Tapestry pp. 628) A templated class cannot be

Fundemental Dilemma in using Templated Classes (Tapestry pp. 628) A templated class cannot be compiled without instantiating. The reason is simple, there is nothing to be compiled in the template itself! Even if you have both class declaration (. h) and class implementation in the same translation unit (which is the case in linkedlisttemplate. cpp since we include linkedlisttemplate. h at the beginning) compilation means nothing without knowing the corresponding real types for the templates. – – – Compilation succeeds but does not produce the expected object code for the class member functions Thus when you use the class member functions in the main program, the linker will complain by some unresolved external symbol errors. Let us generate this case in our templated Linked List class. Types corresponding to templates become apparent when we generate objects in the main program. E. g. Linked. List <string> strlist; – – Thus, class declaration (linkedlisttemplate. h), member function implementations (linkedlisttemplate. cpp) and the user program (linkedlisttemplatedemo. cpp) must be in the same translation unit. There are some ways of doing this (see next slide) 24

Solutions to Fundemental Dilemma Solution 1: Have both class declaration and implementation in the

Solutions to Fundemental Dilemma Solution 1: Have both class declaration and implementation in the same file (name is not important but say. h file) and include it at the beginning of the user program file. Solution 2 (widely used): Keep separate. h (class declaration ) and. cpp (class implementation) files – But at the end of the class header file (linkedlisttemplate. h) put #include "linkedlisttemplate. cpp" – Include the header file (linkedlisttemplate. h) at the beginning of the user program, as usual. In this way, translation unit includes everything – Caution 1: Do not add class implementation file (linkedlisttemplate. cpp) to the project; this would cause lots of redefinition errors. – Caution 2: Since the header file is also included at the beginning of linkedlisttemplate. cpp (which actually is not needed in this approach), if you do not make the classical control to guard multiple header file inclusion you can have infinite inclusion. Thus you have to have the following structure in the header file: #ifndef _LINKEDLISTTEMPLATE_H #define _LINKEDLISTTEMPLATE_H // the class definition #endif – Let's use this approach in our case Solution 3: Keep separate. h (class declaration ) and. cpp (class implementation) files and include both at the beginning of the user program 25

Function pointers 26

Function pointers 26

Function Pointers (Pointers to Functions) Consider the following scenario: You have 2 or more

Function Pointers (Pointers to Functions) Consider the following scenario: You have 2 or more functions with the same prototype other than their names – i. e. they have same return types and same types for the parameters – Example: double f 1 (int, double); double f 2 (int, double); . . . – In another function (say my. F), you want to call one of these functions, but you do not know which one while implementing my. F – So you want to make the "function to call" a parameter of my. F and pass the actual function to call as an argument while you call my. F Can you pass a function as parameter to another function? Yes, using pointers to functions. 27

Pointers to Functions You can generate a pointer to a function using the following

Pointers to Functions You can generate a pointer to a function using the following syntax Type (* Pointer. Name)(Parameter list ) – Type must match the function's return type – Parameter list must match the function's parameter list – Don't forget parentheses before and after * Pointer. Name When you want to assign a function to a function pointer, you get the address of function using & and assign it to the function pointer: Pointer. Name = & Function. Name; When you want to call the function using function pointer use: (* Pointer. Name)(Argument list) See an example in funcptr. cpp 28

END OF THIS PPT SKIP THE REST (actually the rest of this ppt file

END OF THIS PPT SKIP THE REST (actually the rest of this ppt file is not shown in slide show mode since the rest of the slides are hidden) 29