Tải bản đầy đủ (.ppt) (44 trang)

bài giảng chú giải trình hướng đối tượng bài 3

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (271.92 KB, 44 trang )

UNIT-III
Template

Easily create a large range of related functions or classes

Function template - the blueprint of the related functions

Template function - a specific function made from a function
template

Class templates

Allow type-specific versions of generic classes

Syntax for class template:
template <class T>
class ClassName{
definition
}

Need not use "T", any identifier will work
Function templates

Syntax:
template<class type> function_declaration;
-Or-
template<typename type> function_declaration;

Function templates are special functions that can operate with generic
types. This allows us to create a function template whose functionality
can be adapted to more than one type or class without repeating the


entire code for each type.
In C++ this can be achieved using template parameters. A template
parameter is a special kind of parameter that can be used to pass a type
as argument: just like regular function parameters can be used to pass
values to a function, template parameters allow to pass also types to a
function. These function templates can use these parameters as if they
were any other regular type
declaring function templates

template <class identifier> function_declaration;

template <typename identifier> function_declaration;
The only difference between both prototypes is the use of
either the keyword class or the keyword typename. Its use
is indistinct, since both expressions have exactly the same
meaning and behave exactly the same way.
example
// function template
#include <iostream>
using namespace std;
template <class T>
T GetMax (T a, T b)
{
T result;
result = (a>b)? a : b;
return (result);
}
Continue….
int main ()
{

int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax<int>(i,j);
n=GetMax<long>(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
Class templates
#include <iostream>
using namespace std;
template <class T>
class mypair
{
T a, b;
public:
mypair (T first, T second)
{
a=first;
b=second;
}
T getmax ();
};

Cont…
template <class T>
T mypair<T>::getmax ()
{
T retval;
retval = a>b? a : b;

return retval;
}
Cont…
int main ()
{
mypair <int> myobject (100, 75);
cout << myobject.getmax();
return 0;
}
Introduction to Exception Handling

An
exception
exception is any unusual event, either
erroneous or not, detectable by either hardware or
software, that may require special processing

Without
exception handling
exception handling

When an exception occurs, control goes to the
operating system, where typically

an error message is displayed

the program is terminated

With exception handling


Programs are allowed to trap exceptions

There is a possibility to fix the problem and continuing
execution
The Throw-Catch Game
catch
throw
return
call

Error handling is a path parallel to the return path

When a throw is activated stack unwinding occurs and destructors are
activated

If, during a throw, a destructor throws additional exception
std::terminate() is called

we cannot handle two exceptions
Example

Lets consider class stack
const int MAX_ELEM=10;
template <typename T, int size=MAX_ELEM>
class Stack {
T m_arr[size];
int m_index;
public:
Stack() : m_index(0) {}
void Push(T elemP) {

m_arr[m_index] = elemP;
m_index++; }
T& Pop() {
m_index ;
return m_arr[m_index]; }
int Index() const {
return m_index; }
};
Class Anomalies

What happens if we pop() an empty stack?

What happens if we push() on a full stack?

We decide that these situations need to be handled in a
special manner, since they are anomalies of the class
behavior

First we define classes of exceptions which may be
thrown

Upon anomaly detection, we will throw an exception
class popOnEmpty { /* … */ }
class pushOnFull { /* … */ }
Exception Handling Syntax

Exception Handlers
try {
code that is expected to raise an exception
}

catch (formal parameter) {
handler code
}
Example

Our code would now change

No need to examine the returned value for checking for
success.
. . .
void Push(T elemP) {
if (m_index>=size)
throw pushOnFull(); // an object is throws
m_arr[m_index] = elemP;
m_index++; }
T& Pop() {
if (m_index<=0)
throw popOnEmpty(); // an object is thrown
m_index ;
return m_arr[m_index]; }
. . .
};
Try…Catch Blocks

Wrap the code which needs to be “exception sensitive”,
and react to raised exceptions, in a
try {…} catch {…}
try {…} catch {…}
blocks


The client’s code look now as following
int main() {
try{
Stack<int> si;
si.Pop();
si.Push(5);
si.Pop();
}
catch (popOnEmpty) {
cout << "stack is empty !!" << endl;
}
catch (popOnFull) {
cout << "stack is Full !!" << endl;
}
};
Try…Catch Blocks

When exception is thrown, execution resumes in the “closest” catch
clause handling the exception

If no catch clause exists capable of handling the exception, program
execution resumes at the terminate() function

Variables declared within the try block cannot be referred to at the
catch clause, since they are local to the block
int main() {
try{
Stack<int> si;
si.Pop(); // ERROR!
cout << “This line will not be printed” << endl;

si.Push(5);
si.Pop();
}
catch (popOnEmpty) {
cout << "stack is empty !!" << endl;
}
cout << “Execution resumes here” << endl;
};
try catch syntax

Form is:
try { // code
. . .
}
catch (ExceptionType_1 e)
{ handle exception 1}
catch (ExceptionType_2 e)
{ handle exception 2 }

catch (ExceptionType_N e)
{ handle exception N }
Throwing Objects

Why throw an object?

Additional data encapsulated

An object is created upon invoking the throw statement

Can be created with additional data, passed to Ctor


Object is destroyed after the catch clause ends
Stack Unwinding

Up the chain of nested function calls, a suitable catch
clause is searched for

Upon functions and compound statements exit, stack is
being unwound

Lifetime of local variables ends

Destructors are called

If no handler is supplied,
terminate()
terminate() is called

Since exception is a situation, where the program cannot continue
execution in a normal manner

By default
terminate()
terminate() calls
abort()
abort()

Similar to function call behavior

But information to set up a function call is not available at compile

time, run-time support is needed
Re-throwing and Catch All

After some corrective action, a catch clause may
throw an exception to be further handled, passing
the exception to another catch clause, by throw
void func() {
try{
//code that might throw bad_alloc error
}
catch (bad_alloc e) {
// do what can be done here
throw;
}
}
Re-throwing and Catch All

General exception handling can be specified

If specified with combination, must be specified
last, since evaluation is evaluated in turn
catch (popOnEmpty e) {
// something
}
catch (popOnFull e) {
// something
}
catch (…) { // handle every exception
// something
}

Exception Specification

Function interface need to be as precise as
possible, it is the contract between several codes

Client code may need to prepare for specific
handling

Best is to provide exception specification with the
method declaration

This will help the compiler to check consistency, to
check that no other exceptions are thrown

It follows the function parameter list
Exception Specification
//. . .
void Push(T elemP) throw(pushOnFull) {
if (m_index>=size)
throw pushOnFull(); // an object is throws
m_arr[m_index] = elemP;
m_index++; }
T& Pop() throw(popOnEmpty) {
if (m_index<=0)
throw popOnEmpty(); // an object is thrown
m_index ;
return m_arr[m_index]; }
//. . .
};
Nesting try Blocks


Exceptions are always handled by
closest matching handler
try {
try {
throw 5;
} catch (int x)
{
cout << x << endl; // exception will be caught here
}
} catch (int x)
{
cout << x-5 << endl;
}

×