Presentation is loading. Please wait.

Presentation is loading. Please wait.

This lecture introduces templates, which are a C++ feature that easily permits the reuse of existing code for new purposes. This presentation shows how.

Similar presentations


Presentation on theme: "This lecture introduces templates, which are a C++ feature that easily permits the reuse of existing code for new purposes. This presentation shows how."— Presentation transcript:

1 This lecture introduces templates, which are a C++ feature that easily permits the reuse of existing code for new purposes. This presentation shows how to implement and use the simplest kinds of templates: template functions. Template Functions

2 Template functions Sometimes as we are designing or testing software, we find a need for a single algorithm that can be applied to objects of different data types Sometimes as we are designing or testing software, we find a need for a single algorithm that can be applied to objects of different data types We want to be able to describe the algorithm without having to specify the data types of the items being manipulated. We want to be able to describe the algorithm without having to specify the data types of the items being manipulated. Such an algorithm is referred to as a generic algorithm. Such an algorithm is referred to as a generic algorithm. C++ supports this using: function overloading and template functions C++ supports this using: function overloading and template functions

3 Function overloading continued In previous lectures we introduced function overloading, i.e. the use of the same name for different functions as long as their parameter types are sufficiently different for the compiler to tell them apart In previous lectures we introduced function overloading, i.e. the use of the same name for different functions as long as their parameter types are sufficiently different for the compiler to tell them apart Lets look at an example to remind ourselves Lets look at an example to remind ourselves

4 Function overloading continued To print six data types we could write: To print six data types we could write: void PrintInt(int n){ void PrintInt(int n){ cout<<“***Debug***” << endl; cout<<“Value is ” << n << endl; }

5 Function overloading continued void PrintChar(char n){ cout<<“***Debug***” << endl; cout<<“Value is ” << n << endl; } void PrintFloat(float n){ cout<<“***Debug***” << endl; cout<<“Value is ” << n << endl; }

6 Function overloading continued void PrintDouble(double d){ cout<<“***Debug***” << endl; cout<<“Value is ” << d << endl; }...

7 The solution to previous problem Instead of having different names for all these similar functions we can use function overloading by giving them all the same name print Instead of having different names for all these similar functions we can use function overloading by giving them all the same name print void Print(int n) { cout<<“***Debug***” << endl; cout<<“Value is ” << n << endl; }

8 The solution continued void Print(char n){ cout<<“***Debug***” << endl; cout<<“Value is ” << n << endl; } void Print(float x){ cout<<“***Debug***” << endl; cout<<“Value is ” << x << endl; }..

9 The solution continued The code that calls these functions now looks like this The code that calls these functions now looks like this Print(someInt); Print(someInt); Print(someChar); Print(someChar); Print(someFloat); Print(someFloat); We can think of Print as a generic algorithm in the sense that the algorithm itself-that of printing the string “***Debug***” and then the value of a variable is independent of the data type of the variable being printed. We can think of Print as a generic algorithm in the sense that the algorithm itself-that of printing the string “***Debug***” and then the value of a variable is independent of the data type of the variable being printed.

10 How does this work When our program is compiled the compiler encounters six different functions named Print but gives them six different names internally. When our program is compiled the compiler encounters six different functions named Print but gives them six different names internally. We do not know those names but for the sake of discussion let us assume the names are Print_int, Print_char and so on. When the compiler encounters Print(someVar) We do not know those names but for the sake of discussion let us assume the names are Print_int, Print_char and so on. When the compiler encounters Print(someVar)

11 How does this work continued The compiler must determine which of our six functions to invoke, to do so the compiler compares the type of the actual argument with the types of the formal parameters of the six functions. The compiler must determine which of our six functions to invoke, to do so the compiler compares the type of the actual argument with the types of the formal parameters of the six functions. Above if someVar is of type int, then the compiler generates code to call Print_int (i.e. the one requiring an integer), if someVar was of type float then Print_float is invoked and so on. Above if someVar is of type int, then the compiler generates code to call Print_int (i.e. the one requiring an integer), if someVar was of type float then Print_float is invoked and so on.

12 Function Overloading continued Despite the benefits of function overloading in our print function example we still had to supply six distinct function definitions Despite the benefits of function overloading in our print function example we still had to supply six distinct function definitions This is Okay for functions with few lines of code, but what it the functions themselves were quite complicated This is Okay for functions with few lines of code, but what it the functions themselves were quite complicated Copy and paste does resolve the matter in some sense but we will have to look for a better approach Copy and paste does resolve the matter in some sense but we will have to look for a better approach

13 Here is a small function that you might write to find the maximum of two integers. int max(int a, int b) { if (a > b) return a; else return b; } Finding the Maximum of Two Integers

14 Here is a small function that you might write to find the maximum of two doubles. double max(double a, double b) { if (a > b) return a; else return b; } Finding the Maximum of Two Doubles

15 Here is a small function that you might write to find the maximum of two Knafns. Knafn max(Knafn a, Knafn b) { if (a > b) return a; else return b; } Finding the Maximum of Two Knafns

16 Suppose your program uses 100,000,000 different data types, and you need a maximum function for each... int maximum(Knafn a, Knafn b) { if (a > b) return a; else return b; } One Hundred Million Functions... int maximum(Foo a, Foo b) { if (a > b) return a; else return b; } int maximum(Poo a, Poo b) { if (a > b) return a; else return b; } int maximum(Noo a, Noo b) { if (a > b) return a; else return b; } int maximum(Moo a, Moo b) { if (a > b) return a; else return b; } int maximum(Loo a, Loo b) { if (a > b) return a; else return b; } int maximum(Koo a, Koo b) { if (a > b) return a; else return b; } int maximum(Joo a, Joo b) { if (a > b) return a; else return b; } int maximum(Ioo a, Ioo b) { if (a > b) return a; else return b; } int maximum(Hoo a, Hoo b) { if (a > b) return a; else return b; } int maximum(Goo a, Goo b) { if (a > b) return a; else return b; } int maximum(Doo a, Doo b) { if (a > b) return a; else return b; } int maximum(Coo a, Coo b) { if (a > b) return a; else return b; } int maximum(Boo a, Boo b) { if (a > b) return a; else return b; } int maximum(Knafn a, Knafn b) { if (a > b) return a; else return b; } int maximum(Foo a, Foo b) { if (a > b) return a; else return b; } int maximum(Poo a, Poo b) { if (a > b) return a; else return b; } int maximum(Noo a, Noo b) { if (a > b) return a; else return b; } int maximum(Moo a, Moo b) { if (a > b) return a; else return b; } int maximum(Loo a, Loo b) { if (a > b) return a; else return b; } int maximum(Koo a, Koo b) { if (a > b) return a; else return b; } int maximum(Joo a, Joo b) { if (a > b) return a; else return b; } int maximum(Ioo a, Ioo b) { if (a > b) return a; else return b; } int maximum(Hoo a, Hoo b) { if (a > b) return a; else return b; } int maximum(Goo a, Goo b) { if (a > b) return a; else return b; } int maximum(Doo a, Doo b) { if (a > b) return a; else return b; } int maximum(Coo a, Coo b) { if (a > b) return a; else return b; } int maximum(Boo a, Boo b) { if (a > b) return a; else return b; } int maximum(Knafn a, Knafn b) { if (a > b) return a; else return b; } int maximum(Foo a, Foo b) { if (a > b) return a; else return b; } int maximum(Poo a, Poo b) { if (a > b) return a; else return b; } int maximum(Noo a, Noo b) { if (a > b) return a; else return b; } int maximum(Moo a, Moo b) { if (a > b) return a; else return b; } int maximum(Loo a, Loo b) { if (a > b) return a; else return b; } int maximum(Koo a, Koo b) { if (a > b) return a; else return b; } int maximum(Joo a, Joo b) { if (a > b) return a; else return b; } int maximum(Ioo a, Ioo b) { if (a > b) return a; else return b; } int maximum(Hoo a, Hoo b) { if (a > b) return a; else return b; } int maximum(Goo a, Goo b) { if (a > b) return a; else return b; } int maximum(Doo a, Doo b) { if (a > b) return a; else return b; } int maximum(Coo a, Coo b) { if (a > b) return a; else return b; } int maximum(Boo a, Boo b) { if (a > b) return a; else return b; }

17 This template function can be used with many data types. template Item max(Item a, Item b) { if (a > b) return a; else return b; } A Template Function for Maximum

18 When you write a template function, you choose a data type for the function to depend upon... template Item max(Item a, Item b) { if (a > b) return a; else return b; } A Template Function for Maximum

19 A template prefix is also needed immediately before the function’s implementation: template Item max(Item a, Item b) { if (a > b) return a; else return b; } A Template Function for Maximum

20 Once a template function is defined, it may be used with any adequate data type in your program... template Item max(Item a, Item b) { if (a > b) return a; else return b; } Using a Template Function cout << max(1,2); cout << max(1.3, 0.9);...

21 Here is another function that can be made more general by changing it to a template function: int array_max(int data[ ], size_t n) { size_t i; int answer; assert(n > 0); answer = data[0]; for (i = 1; i < n; i++) if (data[i] > answer) answer = data[i]; return answer; Finding the Maximum Item in an Array

22 Here is the template function: template Item array_max(Item data[ ], size_t n) { size_t i; Item answer; assert(n > 0); answer = data[0]; for (i = 1; i < n; i++) if (data[i] > answer) answer = data[i]; return answer; } Finding the Maximum Item in an Array

23 Defining a Function Template In C++ a function template allows you to write a function definition with “blanks” left in the definition to be filled in by the calling code. In C++ a function template allows you to write a function definition with “blanks” left in the definition to be filled in by the calling code. Most often the “blanks” to be filled in are the names of the data types. Most often the “blanks” to be filled in are the names of the data types. Here is a function template for the Print function met earlier Here is a function template for the Print function met earlier

24 Function template definition template template void Print (SomeType val) { cout<<“***Debug***” << endl; cout<<“Value is ” << val << endl; }

25 Function templates continued This function template begins with template, and SomeType is known as the template parameter. This function template begins with template, and SomeType is known as the template parameter. You can use any identifier for the template parameter, we used SomeType in this example You can use any identifier for the template parameter, we used SomeType in this example

26 Function Template Syntax Syntax Syntax template FunctionDefinition

27 continued Where FunctionDefinition is an ordinary function definition. Where FunctionDefinition is an ordinary function definition. The full syntax description of TemplateParamList in C++ is quite complicated, and we simplify if for out purposes The full syntax description of TemplateParamList in C++ is quite complicated, and we simplify if for out purposes TemplateParamList is a sequence of one or more parameter declarations separated by commas, where each is defined as follows TemplateParamList is a sequence of one or more parameter declarations separated by commas, where each is defined as follows

28 Instantiating a Function Template Given that we have written our Print function template, we can make function calls as follows Given that we have written our Print function template, we can make function calls as follows Print (sum); Print (initial); Print (angle);

29 Continued In this code the data name enclosed in angle brackets is called the template argument. In this code the data name enclosed in angle brackets is called the template argument. At compile time the compiler generates (instantiates) three different functions and gives each its own internal name. At compile time the compiler generates (instantiates) three different functions and gives each its own internal name. The three new functions are called template functions or generated functions The three new functions are called template functions or generated functions

30 continued The first time the compiler encounters Print in the calling code, it generates a new function by substituting float for every occurrence of SomeType in the function Template: The first time the compiler encounters Print in the calling code, it generates a new function by substituting float for every occurrence of SomeType in the function Template: void Print(SomeType val) { cout<<“***Debug***” << endl; cout<<“Value is ” << val << endl; } SomeType float

31 Things to note There are two things to note about template functions. First the function template uses the reserved word class in its parameter list i.e., template. There are two things to note about template functions. First the function template uses the reserved word class in its parameter list i.e., template. However the word class in this context is simply required syntax and does not mean that the callers template argument must be the name of a C++ class. However the word class in this context is simply required syntax and does not mean that the callers template argument must be the name of a C++ class. You can use the reserved word typename instead of class if you wish You can use the reserved word typename instead of class if you wish

32 Program templateFn1.cpp See example TemplateFn1.cpp See example TemplateFn1.cpp The line template void swapargs(X &a, X &b) tell the compiler two things that a template is being created and that a generic definition is beginning. The line template void swapargs(X &a, X &b) tell the compiler two things that a template is being created and that a generic definition is beginning. Here X is a generic type that is used as a place holder. Here X is a generic type that is used as a place holder. After the template portion the function swapargs() is declared using X as the data that will be swapped. After the template portion the function swapargs() is declared using X as the data that will be swapped. In main swapargs() is called using three different type of data, ints, floats and chars. Because swapargs() is a generic function the compiler automaticaly creates three versions of swapargs(): one for ints, floats and chars respectively In main swapargs() is called using three different type of data, ints, floats and chars. Because swapargs() is a generic function the compiler automaticaly creates three versions of swapargs(): one for ints, floats and chars respectively

33 Important terms Generic function-as function definition preceded by a template statement are also called a template function Generic function-as function definition preceded by a template statement are also called a template function When the compiler creates a specific version of this function it is said to have created a specialization, this is also called a generated function When the compiler creates a specific version of this function it is said to have created a specialization, this is also called a generated function

34 Important points Since C++ doe not recognize end-of-line as a statement terminator, the template portion of a template function definition does not have to be on the same line as the function’s name. Since C++ doe not recognize end-of-line as a statement terminator, the template portion of a template function definition does not have to be on the same line as the function’s name. So we could have written So we could have written

35 Important template template void swapargs(X &a, X &b) { X temp; temp = a; a=b;b=temp;}

36 continued If you use this form it is important to understand that no other statements can occur between the template statement and the start of the generic function (template fn). If you use this form it is important to understand that no other statements can occur between the template statement and the start of the generic function (template fn). The following program will not compile The following program will not compile See TemplateFn2.cpp See TemplateFn2.cpp

37 A function with two Generic types See example TemplateFn3.cpp See example TemplateFn3.cpp In this example, the place holder types type1 and type2 are replaced by the compiler with the data types int and char*, and double and long respectively when the compiler generates specific instances of myfunc() within main In this example, the place holder types type1 and type2 are replaced by the compiler with the data types int and char*, and double and long respectively when the compiler generates specific instances of myfunc() within main

38 Point to note REMEMBER: When you create a template function you are in essence allowing the compiler to generate as many different versions of that function as are necessary for handling the various ways that your program calls the function REMEMBER: When you create a template function you are in essence allowing the compiler to generate as many different versions of that function as are necessary for handling the various ways that your program calls the function

39 Explicitly Overloading a Generic Function See TemplateFn4.cpp See TemplateFn4.cpp Even though a generic function overloads itself as needed you can explicitly overload one too. Even though a generic function overloads itself as needed you can explicitly overload one too. This is called explicit specialization. If you overload a generic function, then that overloaded function overrides (or “hides) ”the generic function relative to that specific version. This is called explicit specialization. If you overload a generic function, then that overloaded function overrides (or “hides) ”the generic function relative to that specific version.

40 Explanation As the comments inside the program indicate when swappargs(i,j) is called, it invokes the explicitly overloaded version of swapargs() defined in the program. As the comments inside the program indicate when swappargs(i,j) is called, it invokes the explicitly overloaded version of swapargs() defined in the program. Thus the compiler does not generate this version of the generic swapargs() function because the generic function is overridden by the explicit overloading Thus the compiler does not generate this version of the generic swapargs() function because the generic function is overridden by the explicit overloading

41 New syntax for specializaton C++ has introduced syntax that allows explicit specialization of a function. This is shown below for swapargs() C++ has introduced syntax that allows explicit specialization of a function. This is shown below for swapargs() template <> void swapargs(int &a, int &b){ int temp;temp=a; a=b;b=temp; cout<< “Inside swapargs int specialization” << endl; }

42 Explanation As you can see the new-style syntax uses the template<> construct to indicate specialization. As you can see the new-style syntax uses the template<> construct to indicate specialization. The type of data for which specialization is being created is placed inside the angle brackets following the function name The type of data for which specialization is being created is placed inside the angle brackets following the function name

43 Overloading a Function Template In addition to creating explicit overloaded versions of a generic function, you can overload the template specification, itself. To do so simply create another version of the template that differs from any others in its parameter list. See TemplateFn5.cpp See TemplateFn5.cpp Here the template for f() is overloaded to accept either one or two parameters Here the template for f() is overloaded to accept either one or two parameters

44 Using standard parameters with template functions You can mix standard parameters with generic type parameters in a template function. You can mix standard parameters with generic type parameters in a template function. These non-generic parameters work just like they do with any other function These non-generic parameters work just like they do with any other function See TemplateFn6.cpp See TemplateFn6.cpp

45 Explanation In the program the function repeat() displays the first argument the number of times requested by the second argument. In the program the function repeat() displays the first argument the number of times requested by the second argument. Since the first argument is a generic type, repeat can be used to display any type of data. Since the first argument is a generic type, repeat can be used to display any type of data. The times parameter is a standard call-by- reference parameter. The times parameter is a standard call-by- reference parameter.

46 Creating a generic abs() Function Lets look again at a function computing the absolute value of its argument Lets look again at a function computing the absolute value of its argument See example abs1.cpp See example abs1.cpp Explanation to follow Explanation to follow

47 Generic classes In addition to generic functions you can also define a generic class. In addition to generic functions you can also define a generic class. When you do this you create a class that defines all the algorithms used by that class; however the actual type of the data being manipulated will be specified as a parameter when objects of that class are created. When you do this you create a class that defines all the algorithms used by that class; however the actual type of the data being manipulated will be specified as a parameter when objects of that class are created. Useful when a class uses logic that can generalised, e.g. the same algorithm that maintains a queue of integers will also work for a queue of characters. Useful when a class uses logic that can generalised, e.g. the same algorithm that maintains a queue of integers will also work for a queue of characters.

48 Syntax template class class_name{ template class class_name{..} Here Ttype is the placeholder type name, which will be specified when a class is instantiated. See example queue1.cpp (and explain)

49 Member functions Member functions of a generic class are themselves automatically generic, you don’t need to use a template to explicitly specify them as such. Member functions of a generic class are themselves automatically generic, you don’t need to use a template to explicitly specify them as such. A character queue and a floating point queue are created but any data can be used. A character queue and a floating point queue are created but any data can be used.

50 A template function depends on an underlying data type. SummarySummary

51 Polymorphism and Overloading in C++ Lecture 8b Polymorphism and Overloading

52 Overview Overloading Overloading Ambiguous function calls Ambiguous function calls Unambiguous function calls Unambiguous function calls Polymorphism Polymorphism Virtual functions Virtual functions

53 Keywords for Today Polymorphism Polymorphism Overloading Overloading Ambiguous Ambiguous Unambiguous Unambiguous Virtual functions Virtual functions

54 Function overloading In C++ two or more functions can share the same name as long as their signatures (i.e. parameter declaration are different). In C++ two or more functions can share the same name as long as their signatures (i.e. parameter declaration are different). In this set the functions are said to be overloaded, and the process is referred to as function overloading In this set the functions are said to be overloaded, and the process is referred to as function overloading Lets consider an example Lets consider an example See example Overloading1.cpp See example Overloading1.cpp

55 Overloading1.cpp example The program produces the following output: The program produces the following output: In f(int), i is 10 In f(int,int), i is 10, j is 20 In f(double), k is 12.23

56 Example continued As one can see f() is overloaded three times i.e. there are three different versions of it, each version requiring different parameters in the function call. As one can see f() is overloaded three times i.e. there are three different versions of it, each version requiring different parameters in the function call. Because the parameter list is different for each function call the compiler is able to call the correct version of the function. Because the parameter list is different for each function call the compiler is able to call the correct version of the function.

57 Example continued The compiler uses the type and/or number of arguments as its guide to determining which version of an overloaded function to call. The compiler uses the type and/or number of arguments as its guide to determining which version of an overloaded function to call. Thus overloaded functions must differ in the type and/or number of their parameters. Thus overloaded functions must differ in the type and/or number of their parameters. While overloaded functions may have different return types, the return type alone is not sufficient to distinguish two versions of a function. While overloaded functions may have different return types, the return type alone is not sufficient to distinguish two versions of a function. To better understand this lets look at another example. To better understand this lets look at another example.

58 Example Overloading2.cpp This program creates three similar but different functions called abs, each of which returns the absolute value of its argument. This program creates three similar but different functions called abs, each of which returns the absolute value of its argument. The compiler knows which function to use in each given situation because of the type of the argument. The compiler knows which function to use in each given situation because of the type of the argument. Thus the name abs represents the general action that is being performed. Thus the name abs represents the general action that is being performed. It is left to compiler to choose the correct specific version for a particular circumstance. It is left to compiler to choose the correct specific version for a particular circumstance.

59 When do we overload? When we overload a function, each version of that function can perform and activity one desires. That is there is no rule that states that overloaded functions must relate to one another. When we overload a function, each version of that function can perform and activity one desires. That is there is no rule that states that overloaded functions must relate to one another. From a stylistic point of view function overloading implies a relationship. Thus while you could use the same name to overload unrelated functions you should not. From a stylistic point of view function overloading implies a relationship. Thus while you could use the same name to overload unrelated functions you should not. E.g. you could use the name sqr() to create functions that return the square of an int and the square root of a double. But these two operations are different and applying function overloading in this manner defeats the original purpose, this would be considered bad practice. E.g. you could use the name sqr() to create functions that return the square of an int and the square root of a double. But these two operations are different and applying function overloading in this manner defeats the original purpose, this would be considered bad practice.

60 A C++ reminder When C++ was created, overloaded functions had to be explicitly declared as such using the overload keyword. When C++ was created, overloaded functions had to be explicitly declared as such using the overload keyword. The overload keyword is no longer required or supported by C++. The overload keyword is no longer required or supported by C++. In fact it is not even defined as a keyword by standard C++. But in older books you may encounter it. The general form was In fact it is not even defined as a keyword by standard C++. But in older books you may encounter it. The general form was overload func_name; overload func_name; E.g. you would write overload abs(); E.g. you would write overload abs(); Most compilers would not accept this now. Most compilers would not accept this now.

61 Default Function Arguments In C++ you can give a parameter a default value that is automatically used when no arguments corresponding to that parameter is specified in a function call. In C++ you can give a parameter a default value that is automatically used when no arguments corresponding to that parameter is specified in a function call. The syntax is similar to variable initialization The syntax is similar to variable initialization

62 Example defaultfunction1.cpp defaultfunction1.cpp myfunc() can be called by one of the three ways shown here: myfunc() can be called by one of the three ways shown here: Myfunc(198.234, ‘A’); Myfunc(198.234, ‘A’); Myfunc(10.1); Myfunc(10.1); Myfunc(); Myfunc();

63 Explaining example The first call passes the value 198.234 to num and ‘A’ to ch The first call passes the value 198.234 to num and ‘A’ to ch The second call automatically gives num the value 10.1 and allows ch to default to ‘X’ The second call automatically gives num the value 10.1 and allows ch to default to ‘X’ Finally the third call cause both num and ch to default. Finally the third call cause both num and ch to default.

64 Why use default argument? One reason is that default arguments are included in C++ is to enable the programmer to manage greater complexity. One reason is that default arguments are included in C++ is to enable the programmer to manage greater complexity. To illustrate this lets look at the clrscr() example (i.e defaultfunction2.cpp in the folder) To illustrate this lets look at the clrscr() example (i.e defaultfunction2.cpp in the folder)

65 clrscr() example explained The clrscr() function clears the screen by outputting a series of line feeds (not the most efficient way to do it). The clrscr() function clears the screen by outputting a series of line feeds (not the most efficient way to do it). Since a very common video mode displays 25 lines of text the default argument of 25 is provided. Since a very common video mode displays 25 lines of text the default argument of 25 is provided. However since some terminals can display more or less than 25 lines you can override the default argument by specifying another explicitly However since some terminals can display more or less than 25 lines you can override the default argument by specifying another explicitly

66 Things to note The default values must be specified only once, and this specification MUST happen the first time the function is declared within the file. The default values must be specified only once, and this specification MUST happen the first time the function is declared within the file. In the previous example the default argument was specified in clrscr()’s prototype. In the previous example the default argument was specified in clrscr()’s prototype. If you try to specify new (or even the same) default values in clrscr()’s definition the compiler will give an error message If you try to specify new (or even the same) default values in clrscr()’s definition the compiler will give an error message

67 Another point to note It is important to note that all parameters that take default values must appear to the right of those that do not. E.g the following prototype is invalid It is important to note that all parameters that take default values must appear to the right of those that do not. E.g the following prototype is invalid void f(int a=1, int b); //wrong

68 Another point to note Once you have begun defining parameters that take default values, you cannot specify a non-defaulting parameter. That is a declaration like the following: Once you have begun defining parameters that take default values, you cannot specify a non-defaulting parameter. That is a declaration like the following: int myfun(float f, char str, int i=10, int j) Since i has been given a default value j, must also be given one too.

69 Default arguments vs Overloading Suppose we want to create two versions of the standard strcat function. Suppose we want to create two versions of the standard strcat function. One version will operate like strcat() and concatenate the entire contents of one string onto another. One version will operate like strcat() and concatenate the entire contents of one string onto another. The other version will take a third argument that specifies the number of characters to concatenate. The other version will take a third argument that specifies the number of characters to concatenate.

70 The definition of mystrcat() void mystrcat(char *s1, char *s2, int len); void mystrcat(char *s1, char *s2, int len); void mystrcat(char *s1, char *s2); void mystrcat(char *s1, char *s2); The first version will copy len characters from s2 to the end of s1. The second version will copy the entire string pointed to by s2 onto the end of the string pointed to by s1 and will thus operate like strcat() See example DefaultArguementsVsOverloading1.cpp

71 DefaultArguements Vs Overloading1.cpp continued Here mystrcat() concatenates up to len characters from the string pointed to by s2 onto the end of the string pointed to by s1, if len is zero as it will be when it is allowed to default, mystrcat() concatenates the entire string pointed to by s2 onto s1. Here mystrcat() concatenates up to len characters from the string pointed to by s2 onto the end of the string pointed to by s1, if len is zero as it will be when it is allowed to default, mystrcat() concatenates the entire string pointed to by s2 onto s1. So when len=0 the function behaves like strcat(), so default constructors are short-cut ways of function overloading. So when len=0 the function behaves like strcat(), so default constructors are short-cut ways of function overloading.

72 Function overloading and ambiguity Common type of C++ error related to function overloading is ambiguity. Common type of C++ error related to function overloading is ambiguity. It is possible to create a situation when a compiler is unable to determine which correctly defined overloaded function to choose. It is possible to create a situation when a compiler is unable to determine which correctly defined overloaded function to choose. Ambiguous statements are errors and thus the program will not compile. Ambiguous statements are errors and thus the program will not compile.

73 Ambiguity continued The most common type of mistake is that of automatic type conversions. The most common type of mistake is that of automatic type conversions. C++ will automatically attempt to convert the type of the arguments used to call a function into the type of the parameters defined by the function. C++ will automatically attempt to convert the type of the arguments used to call a function into the type of the parameters defined by the function.

74 Example int myfunc(double d); int myfunc(double d);.. cout << myfunc(‘c’); // no error, //conversion applied //conversion applied The character c will be converted into its double equivalent.

75 Demonstration See example FnAmbiguityandOver1.cpp See example FnAmbiguityandOver1.cpp This program does not compile, there is an ambiguity when we write This program does not compile, there is an ambiguity when we write myfunc(10); myfunc(10); The compiler has no way of knowing whether to convert to float or double The ambiguity is not caused by the overloading of myfunc but by the specific call to myfunc()

76 Demonstration See example See exampleFnAmbiguityandOver2.cpp Compiler does not know whether to convert to char or to unsigned char

77 Pointers to derived classes In C++ a base class pointer may also be used to point to an object of any class derived from that base In C++ a base class pointer may also be used to point to an object of any class derived from that base Suppose we have base class B_class and a class called D_class which is derived from B_class. Suppose we have base class B_class and a class called D_class which is derived from B_class. In C++ any pointer declared as a pointer to B_class can also be a pointer to D_class In C++ any pointer declared as a pointer to B_class can also be a pointer to D_class

78 Pointers to derived classes B_class *p; B_class *p; B_class B_obj; B_class B_obj; D_class D_obj; D_class D_obj; The following are now valid p=&B_obj;p=&D_obj;

79 Example continued In this example p can be used to to access all elements of D_ob inherited from B_ob. However elements specific to D_ob can not be references with p In this example p can be used to to access all elements of D_ob inherited from B_ob. However elements specific to D_ob can not be references with p See example PointerInheritance.cpp See example PointerInheritance.cpp

80 Explanation In PointerInheritance1.cpp, the pointer p is defined as a pointer to B_class. In PointerInheritance1.cpp, the pointer p is defined as a pointer to B_class. However it can point to an object of the derived class D_class and can be used to access those elements of the derived class that are inherited from the base class However it can point to an object of the derived class D_class and can be used to access those elements of the derived class that are inherited from the base class Recall that the inheritance in done publicly Recall that the inheritance in done publicly

81 continued But remember a base class pointer cannot access those elements specific to the derived class (without type casting) that is why show_title() is accessed with the dp pointer which is a pointer to the derived class But remember a base class pointer cannot access those elements specific to the derived class (without type casting) that is why show_title() is accessed with the dp pointer which is a pointer to the derived class

82 continued If you want to access elements defined by the derived class by using a base class pointer you must cast it into a pointer of the derived type. The following line of code will properly call the show_title() function of D_obj If you want to access elements defined by the derived class by using a base class pointer you must cast it into a pointer of the derived type. The following line of code will properly call the show_title() function of D_obj ((D_class *)p)->show_title(); ((D_class *)p)->show_title(); The outer set of parentheses is necessary for associating the cast with p and not with the return type of show_title(). This code would be considered bad code. The outer set of parentheses is necessary for associating the cast with p and not with the return type of show_title(). This code would be considered bad code.

83 Virtual functions Run-time polymorphism is achieved through a combination of two features: Run-time polymorphism is achieved through a combination of two features: Inheritance Inheritance Virtual functions Virtual functions A virtual function is declared virtual in a base class and redefined in one or more of the derived classes A virtual function is declared virtual in a base class and redefined in one or more of the derived classes So each derived class can have its own version of a virtual function So each derived class can have its own version of a virtual function

84 Virtual functions When a virtual function is called through a base class pointer C++ determines which version of that function to call based upon the type of the object pointed to by the pointer. When a virtual function is called through a base class pointer C++ determines which version of that function to call based upon the type of the object pointed to by the pointer. This determination is made at run-time This determination is made at run-time

85 Declaring virtual functions One declares a virtual function as virtual inside the base class by preceding it declaration with the keyword virtual. One declares a virtual function as virtual inside the base class by preceding it declaration with the keyword virtual. When a virtual function is redefined in the derived class the keyword virtual need not be included but it is not an error to do so. When a virtual function is redefined in the derived class the keyword virtual need not be included but it is not an error to do so.

86 Virtual functions A class that includes a virtual function is called a polymorphic class. A class that includes a virtual function is called a polymorphic class. See example virtual1.cpp See example virtual1.cpp

87 Output of virtual1.cpp The output as we have seen is: The output as we have seen is: Base Base First derivation First derivation Second derivation Second derivation

88 Examining the program As you can see in base the fn who() is declared virtual. This means that the function can be redefined in derived classes, which has been done in the derived classes As you can see in base the fn who() is declared virtual. This means that the function can be redefined in derived classes, which has been done in the derived classes In main four variables are declared. Since who() is declared virtual, C++ determines at run-time which version of who() is referred to by the type of object pointed to by p. In main four variables are declared. Since who() is declared virtual, C++ determines at run-time which version of who() is referred to by the type of object pointed to by p. In this case p points to an object type base, so the version of who() in base is executed. In this case p points to an object type base, so the version of who() in base is executed. When p is assigned the address of first_obj, who() of this class is now executed. When p is assigned the address of first_obj, who() of this class is now executed.

89 Calling virtual functions The following is also permitted The following is also permitted First_obj.who(); First_obj.who(); But this ignores polymorphic attributes. But this ignores polymorphic attributes. Note redefinition of virtual functions requires identical definitions as opposed to overloading where we must alter the signature. Note redefinition of virtual functions requires identical definitions as opposed to overloading where we must alter the signature. A virtual function must be a member of a class and not a friend. A virtual function must be a member of a class and not a friend.

90 Virtual function are inherited Suppose second_d is derived from first_d instead of base Suppose second_d is derived from first_d instead of base See virtual2.cpp See virtual2.cpp


Download ppt "This lecture introduces templates, which are a C++ feature that easily permits the reuse of existing code for new purposes. This presentation shows how."

Similar presentations


Ads by Google