• Introduction • Function Overloading Vs. Function Templates
• Function Templates • Overloading Function Templates • Class Templates • Class Template And Non-Type Parameters
• Template And Inheritance •Template and Friends •Generic Functions •Applying Generic Functions •Generic Classes •Typename and Export Keyword •Power of Templates INTRODUCTION
• C++ templates • Allow very ‘general’ definitions for functions and classes • Type names are ‘parameters’ instead of actual types • Precise definition determined at run-time
C++ Function Templates
• Approaches for functions that implement identical tasks for different data types – Naïve Approach – Function Overloading – Function Template • Instantiating a Function Templates
6 Approach 1: Naïve Approach
• Create unique functions with unique names for each combination of data types – Difficult to keep track of multiple function names – lead to programming errors
7 Example void PrintInt( int n ) { cout << "***Debug" << endl; cout << "Value is " << n << endl; } void PrintChar( char ch ) { cout << "***Debug" << endl; cout << "Value is " << ch << endl; } void PrintFloat( float x ) To output the traced values, we { insert: … } PrintInt(sum); void PrintDouble( double d ) { PrintChar(initial); … } PrintFloat(angle);
Approach 2: Function Overloading – Review • The use of the same name for different C++ functions, distinguished from each other by their parameter lists • Eliminates the need to come up with many different names for identical tasks. • Reduces the chance of unexpected results caused by using the wrong function name.
9 Example of Function Overloading void Print( int n ) { cout << "***Debug" << endl; cout << "Value is " << n << endl; } void Print( char ch ) { cout << "***Debug" << endl; cout << "Value is " << ch << endl; } To output the traced values, we void Print( float x ) insert: { Print(someInt); Print(someChar); Print(someFloat); }
Approach 3: Function Template
• A C++ language construct that allows the compiler to generate multiple versions of a function by allowing parameterized data types.
FunctionTemplate
Template < TemplateParamList > FunctionDefinition
TemplateParamDeclaration: placeholder
class typeIdentifier typename variableIdentifier
11 Function Template Syntax
• Allow ‘swap values’ of any type variables: template
• Recall: template
• Again: template
• Consider following call: swapValues(int1, int2); • C++ compiler ‘generates’ function definition for two int parameters using template • Likewise for all other types • Needn’t do anything ‘special’ in call • Required definition automatically generated Instantiating a Function Template
• When the compiler instantiates a template, it substitutes the template argument for the template parameter throughout the function template.
TemplateFunction Call
Function < TemplateArgList > (FunctionArgList)
16 Example of a Function Template
Template parameter template
Template To output the traced values, we insert: argument Print
Another Function Template
• Declaration/prototype: template
• Consider function call: showStuff(2, 3.3, 4.4); • Compiler generates function definition • Replaces T with double • Since second parameter is type double • Displays: 2 3.3 4.4 Function Templates vs. Overloading
• Could overload function for char’s: void swapValues(char& var1, char& var2) { char temp; temp = var1; var1 = var2; var2 = temp; } • But notice: code is nearly identical! • Only difference is type used in 3 places Multiple Type Parameters
• Can have: template
template
Stack
Naïve Approach Function Overloading Different Function Definitions Different Function Definitions Different Function Names Same Function Name
Template Functions One Function Definition (a function template) Compiler Generates Individual Functions Class Templates
• Can also ‘generalize’ classes template
• For class template declaration: template
• template
• template
Class Template Definition
template
template
• Notice in member function definitions:
• Each definition is itself a ‘template’
• Requires template prefix before each definition
• Class name before :: is ‘Pair
• Not just ‘Pair’ Generic programming • Generalize algorithms – Sometimes called “lifting an algorithm”
• The aim (for the end user) is – Increased correctness • Through better specification
– Greater range of uses • Possibilities for re-use
– Better performance • Through wider use of tuned libraries • Unnecessarily slow code will eventually be thrown away
• Go from the concrete to the more abstract Templates and Inheritance A class template can be derived from a non-template class
A template class can be derived from a class template
A non-template class can be derived from a class template Overloading Function Templates • You overload functions when you create functions with the same name but with different argument lists • You can overload function templates, as long as each version of the function takes different arguments, allowing the compiler to distinguish between them
1 A main() Function that Uses the Overloaded invert() Function Template Overloading Function Ex10-3.cpp Templates
• Overload the displaySmallest() function template to accept two as well as three arguments
3 Templates and Inheritance A class template can be derived from a non-template class
A template class can be derived from a class template
A non-template class can be derived from a class template A class template can be derived from a non-template class
• For Example : #include • For Example : #include • For Example : #include •catch •throw •Multiple exceptions •Exception with arguments Introduction • Exception: “An abnormal condition that arises in a code sequence at run time”. • An exception is a run-time error. • Exception handling allows us to manage run-time errors in an orderly fashion. Introduction #include // Request two numbers from the user cout << "Please provide two numbers\n"; cout << "First Number: "; cin >> a; cout << "Second Number: "; cin >> b; // Multiply the numbers and display the result c = a * b; cout << "\n" << a << " * " << b << " = " << c << "\n\n"; return 0; } Introduction • When it comes up, the user is asked to simply type two numbers; the program would use them to perform a multiplication and display the result. • Imagine that a user, decides to type the name of a country or somebody’s telephone number as one of the requested values. • Since a program such as this one is not prepared to multiply two strings or one number to a string it would not know what to do. Introduction • The only alternative the compiler would have is to send the problem to the operating system, hoping that the OS would know what to do. • Whenever the compiler is handed a task, it would try to perform the assignment. If it can’t perform the assignment, for any reason it is not prepared for, it would throw an error. • As a programmer, if you can anticipate the type of error that could occur in your program, you can catch the error yourself and deal with it by telling the compiler what to do when this type of error occurs. Introduction • An exception is a situation that would be unusual for the program that is being processed. • An error result or an unpredictable behavior on your program not caused by the operating system but that occurs in your program is called an exception. • The ability to deal with a program’s eventual abnormal behavior is called exception handling. Introduction • Using exception handling, our program can automatically invoke an error-handling routine when an error occurs. • C++ exception handling is built upon three keywords: try, catch, and throw. The Basics • try identifies a code block where exception can occur • throw causes an exception to be raised (thrown) • catch identifies a code block where the exception will be handled (caught) try { … throw an exception … } catch the exception 9 Exception Handling Fundamentals ..try • Error prone program statements that we may want to monitor for generation of exceptions are contained in a try block. • Syntax: try { // try block } Exception Handling Fundamentals..try • When an exception is thrown, the remaining code in the try block is skipped, just as in the case of the return statement in a function, and every auto object created after the try block is entered, is destroyed automatically • The thrown object is caught by the catch block where the execution continues • Then, the execution continues with the next statement after the catch block Exception Handling Fundamentals …throw • If an exception (i.e., an error) occurs within the try block, then that exception is thrown using throw. • Syntax: throw exception; • If an exception is to be caught, then throw must be executed either from within a try block or from any function called from within the try block (directly or indirectly). Exception Handling Fundamentals …catch • The thrown exception is caught, using catch block and processed. • Syntax: catch (type argument) { // catch block } Catching Exceptions • You must supply at least one catch block for a try block • Otherwise compiler error (let's see it in ExceptionSample1.cpp). int main() { int height; cin >> height; try { if (height > 300) throw "height exceeds maximum"; if (height < 30) throw "height below minimum"; cout << "Person is " < • Catch blocks must immediately follow the try block without any program code between them. – Otherwise, compiler error (let's see it in ExceptionSample1.cpp). int main() { int height; cin >> height; try { if (height > 300) throw "height exceeds maximum"; if (height < 30) throw "height below minimum"; cout << "Person is " < cout << "Program Stops " << endl; return 0; } try { Program statements requires monitor for exceptions } catch( type argument ) { Program statements handles for Exception } try { Program statements requires monitor for exceptions } catch( type1 argument ) { catch( type2 argument ) { catch( typen argument ) Program statements{ handles Program for Exception statements handles for ExceptionProgram statements } handles for Exception } } Using try & catch try { Arithmetic int d = 0; int a = 30 / d; throws Exception } catch(int e ) { printf("Division by zero."); } Syntax for Exception Handling Code : try-catch Combined with the try block, the syntax of an exception would be: try { ……….. throw exception; } catch(Argument) { // Catch the exception } Exception Handling Fundamentals NOTE: Throwing an unhandled exception causes the standard library function terminate() to be invoked. By default, terminate() calls abort() to stop your program. Code : try- catch-throw #include Code : try- catch-throw catch (... ) is used to catch(...) catch any unhandled { } exception cout << "\n"; return 0; } Output • If positive integer is given as input Output : Enter Student Age: 1 Student Age: 1 • If negative integer is given as input Output : Enter Student Age: -1 Program will give an abnormal termination error Code : try- catch-throw #include // Request two numbers from the user cout << "Please provide two numbers\n"; Code : try- catch-throw try { cout << "First Number: "; cin >> Number1; cout << "Second Number: "; cin >> Number2; if( Number2 == 0 ) throw (Number2); // Perform a division and display the result Result = Number1 / Number2; cout << "\n" << Number1 << " / " << Number2 << " = " << Result << "\n\n"; } Code : try- catch-throw catch(int i) { cout<<“Exception caught : x = “< return 0; } Output • Please provide two numbers First Number: 126.45 Second Number: 5.52 126.45 / 5.52 = 22.9076 Number1 126.45 Number2: 5.52 Result 22.9076 Output • Please provide two numbers First Number: 126.45 Second Number: 0 Exception caught : x=0 Example: Handling an Attempt to Divide by Zero in C++ #include Example: Handling an Attempt to Divide by Zero in C++ cout< }//try ends Example: Handling an Attempt to Divide by Zero in C++ catch(DivEx & obj) { cout<<“Error caught : ”obj.what(); }//catch ends cout<<“Enter two integer numbers (Ctrl – C to end) “ ; }//while ends return 0; } Throwing an Exception to be Caught by the Calling void Func3() { Code try { void Func4() Function { Func4(); call } if ( error ) Normal throw ErrType(); catch ( ErrType ) return { } } } Return from thrown exception Exception Handling Stack unwinding Occurs when a thrown exception is not caught in a particular scope Unwinding a Function terminates that function • All local variables of the function are destroyed • Invokes destructors • Control returns to point where function was invoked Attempts are made to catch the exception in outer try…catch blocks If the exception is never caught, the function terminate is called Stack unwinding If exception is thrown in a try block (or in a function that is called from a try block or in a function that is called from a function that is called from a try block and so on), all local objects allocated from the runtime stack after the try block was entered are released (go out of scope) and their destructors are called. This process is called stack unwinding. This process guarantees that when we try to recover from an error, there are no inconsistent data in the runtime stack and there is no memory leak Stack unwinding Example If error occurs in the function f2, the int main() { //.... destructors for objects myA, myB and try { myC are called and those objects are Aclass myA; deleted from the stack in the reverse f1(); //.... order of creation and before the } exception is caught. //catch come here } void f1() { Note that this would also return any Bclass myB; dynamically allocated memory used in f2(); //.... those objects (myA, myB, myC), } through their properly implemented void f2() { destructors. Cclass myC; //.... throw "Exception"; } Another example (problematic) • Sometimes stack unwinding does not suffice since it does not return the dynamic memory to heap. try { int * myarr; myarr = new int [LARGECLASS]; Process(myarr); //suppose an exception is thrown in Process function } catch (...) { //Need to free the heap memory pointed by myarr //But there is a problem – cannot refer myarr cout << "Exception caught" << endl; } Another example (acceptable, but questionable solution) • Move myarr definition outside the try block so that catch can refer. • But this time you cannot force myarr pointer to go out of scope by stack unwinding. int * myarr; //moved outside of try try { myarr = new int [LARGECLASS]; Process(myarr); //suppose an exception is thrown in Process function } catch (...) { delete [] myarr; cout << "Exception caught" << endl; } Another example (best solution) • Pure object oriented approach. • Define a class for the array and let the class destructor to handle delete. • Destructor of local objects are automatically called when exception is thrown but before it is caught (this is what stack unwinding is) • CAUTION: You cannot refer to myarr in the catch block, not only due to scope rules, but also due to the fact it has been destructed when the exception is thrown. try { ArrayClass myarr; myarr.Init(); //allocates memory, etc. myarr.Process(); //suppose an exception is thrown in Process function } catch (...) { cout << "Exception caught" << endl; } Rethrowing an Exception • Rethrowing exceptions – Used when an exception handler cannot process an exception – Rethrow exception with the statement: throw; • No arguments • If no exception thrown in first place, calls terminate – Handler can always rethrow exception, even if it performed some processing – Rethrown exception detected by next enclosing try block #include // Throw an exception and immediately catch it. try { • 1.1 cout << "Function throwException\n"; Function throw exception(); // generate exception } prototype catch(exception e) { cout<<“Exception handled in function throw Exception\n”; } throw; // rethrow exception for further processing } cout<< “This should not print\n”; } int main() { try { • 2. Function throwException( ); call cout<< “This should not print\n”; } catch(exception e) • 3. Output { cout<<“Exception handled in main\n”; } cout<<“Program control continues after catch in main\n”; return 0; } Function throwException Exception handled in function throwException • Program Exception handled in main Output Program control continues after catch in main Exception Specifications Exception specification (throw list) means listed exceptions canbe thrown by a function Example: int g( double h ) throw ( a, b, c ) { // function body } Function can throw only listed exceptions or derived types If other type thrown, function unexpected called throw() (i.e., no throw list) states that function will not throw any exceptions In reality, function can still throw exceptions, but calls unexpected (more later) If no throw list specified, function can throw any exception Exception Specifications • int someFunction( double value ) throw ( int, double) { ... } The above example means the someFunction() can throw only int and double type of exception…. If others are thrown it will generate unexpected error. Exception Specifications Example // Example 1(a) int Func(); // can throw anything\ // Example 1(b) int Gunc() throw(); // will throw nothing int Hunc() throw(int , float); // can only throw int or double Exception Specifications Example #include Processing Unexpected Exceptions • C++ has following functions to process unexpected exceptions that are not caught. 1) terminate() 2) abort() Processing Unexpected Exceptions • Function unexpected – Calls the function specified with set_unexpected • Default: terminate • Function terminate – Calls function specified with set_terminate • Default: abort • set_terminate and set_unexpected – Prototypes in Processing Unexpected Exceptions #include } Solution to the above problem is using : • set_terminate and set_unexpected – Prototypes in Processing Unexpected Exceptions #include } catch(one) { cout<<“Exception for one”; } } ..At this point function skip is invoked Exception Handling Constructors, Destructors and Exception Handling If an exception is thrown during construction of an object consisting of subobjects or array elements, destructors are only called for those subobjects or array elements successfully constructed before the exception was thrown. A destructor for a local static object will only be called if the object was successfully constructed. Constructors, Destructors and Exception Handling Example If during stack unwinding a destructor throws an exception and that exception #include Constructors, Destructors and Exception Handling Example class A { A( ) { cout << "In constructor of A" << endl; } ~A() { cout << "In destructor of A" << endl; throw E("Exception thrown in ~A()"); } }; class B { B() { cout << "In constructor of B" << endl; } ~B() { cout << "In destructor of B" << endl; } }; Constructors, Destructors and Exception Handling int main() { The output of this example: set_terminate(my_terminate); try { In try block In constructor of A cout << "In try block" << endl; In constructor of B A a; In destructor of B B b; In destructor of A Call to my_terminate throw E("Exception thrown in try block of main()"); } catch (const char* e) { cout << "Exception: " << e << endl; } catch (...) { cout << "Some exception caught in main()" << endl; } cout << "Resume execution of main()" << endl; } Exception Handling and Inheritance if we put base class catch first before derived class catch then the derived class catch block will never be reached. if we change the order of catch statements then both catch statements become reachable. #include