Function Templates and Generic Programming in C++

3.1.   Template
 
Type-independent patterns that can work with
multiple data types.
Generic programming
Code reusable
Function Templates
These define logic behind the algorithms that
work for multiple data types.
Class Templates
These define generic class patterns into which
specific data types can be plugged in to produce
new classes.
 
4
 
4.2 Function and function templates
 
C++ routines work on specific types.
We often need to write different routines to
perform the same operation on different data
types.
 
int maximum(int a, int b, int c)
 {
      int max = a;
      if (b > max) max = b;
      if (c > max) max = c;
      return max;
}
5
 
Function and function templates
 
float maximum(float a, float b, float c)
 {
      float max = a;
      if (b > max) max = b;
      if (c > max) max = c;
      return max;
}
 
6
 
Function and function templates
 
double maximum(double a, double b, double c)
 {
      double max = a;
      if (b > max) max = b;
      if (c > max) max = c;
      return max;
}
 
 
The logic is exactly the same, but the data type is different.
 
Function 
templates
 allow the logic to be written once and used for all
data types – 
generic function
.
 
How to declare a function template?
 
A function template starts with the keyword template followed by template
parameter/s inside  < > which is followed by function declaration.
 
template <class T>
T someFunction(T arg)
{
   ... .. ...
}
 
 
In the above code, T is a template argument that accepts different data types
(int, float), and class is a keyword.
 
You can also use keyword 
typename
 instead of class in the above example.
 
When, an argument of a data type is passed to someFunction( ), compiler
generates a new version of someFunction() for the given data type.
#include (iostream.h>
Template < class T>
T maximum(T a, T b, T c)
{
 
T max=a;
 
if(b>max)
  
max=b;
 
if (c>max)
  
max=c
 
return max;
}
Void main()
{
 
int x=30,y=67, z=8267;
 
int x=maximum(x,y,z);
 
//other data types
 
double a=6.3, b=653.4, c=75.67;
 
double sup= maximum(a,b,c);
 
cout << “ The maximum number is “<< sup;
}
template <typename T>
void Swap(T &n1, T &n2)
{
 
T temp;
 
temp = n1;
 
n1 = n2;
 
n2 = temp;
}
 
 
int main()
{
 
int i1 = 1, i2 = 2;
 
float f1 = 1.1, f2 = 2.2;
 
char c1 = 'a', c2 = 'b';
 
 
cout << "Before passing data to function template.\n";
 
cout << "i1 = " << i1 << "\ni2 = " << i2;
 
cout << "\nf1 = " << f1 << "\nf2 = " << f2;
 
cout << "\nc1 = " << c1 << "\nc2 = " << c2;
 
 
Swap(i1, i2);
 
Swap(f1, f2);
 
Swap(c1, c2);
 
        cout << "\n\nAfter passing data to function template.\n";
 
cout << "i1 = " << i1 << "\ni2 = " << i2;
 
cout << "\nf1 = " << f1 << "\nf2 = " << f2;
 
cout << "\nc1 = " << c1 << "\nc2 = " << c2;
 
 
return 0;
}
 
10
4.2. Generic Function
 
Generic function to find a maximum value
    (see maximum example).
 
template <class T>
T maximum(T a, T b, T c)
 {
      T max = a;
      if (b > max) max = b;
      if (c > max) max = c;
      return max;
}
 
This function itself is incomplete because the compiler will need to know the
actual type to generate code. So template program are often placed in .h or .
c
pp
files to be included in program that uses the function.
 
C++ compiler will then generate the real function based on the use of the
function template.
 
 
 
11
 
4.2. Generic function Usage(cont..)
 
After a function template is included (or defined),
the function can be used by passing parameters of
real types.
 
Template <class T>
T maximum(T a, T b, T c)
int i1, i2, i3;
Int m = maximum(i1, i2, i3);
 
 
maximum(i1, i2, i3) will invoke the template function
with T==int.
 
 The function returns a value of int type.
 
12
 
Function Templates Usage
 
Each call to 
maximum()
 on a different data type
forces the compiler to generate a different function
using the template. See the maximum example.
One copy of code for many types.
 
  
int i1, i2, i3;
   // invoke int version of maximum
   cout << "The maximum integer value is: "
      << maximum( i1, i2, i3 );
   // demonstrate maximum with double values
   double d1, d2, d3;
   // invoke double version of maximum
   cout << "The maximum double value is: "
      << maximum( d1, d2, d3 );
 
4.3 Class template
 
 
So far the classes that we define use fix data
types.
 
Sometime is useful to allow storage in a class for
different data types.
 
See simplelist1 (a list of int type elements)
example
What if we want to make a simple list of double type?
Copy paste the whole file and replace int with double
Make use of typedef in C++, See simplelist2.
Still need to change one line of code for a new type.
 
13
 
Class template
 
 
Function templates allow writing generic functions
that work on many types.
 
Same idea applies to defining generic classes that
work with many types  -- extract the type to be a
template to make a generic classes.
 
See simplelist
 
14
How to declare a class template?
 
template <class T>
class className
{
   ... .. ...
public:
   T var;
   T someOperation(T arg);
   ... .. ...
};
 
Simple calculator using Class template
 
// Program to add, subtract, multiply and divide two numbers using class template
#include <iostream>
 
template <class T>
class Calculator
{
private:
 
T num1, num2;
public:
 
Calculator(T n1, T n2)
 
{
  
num1 = n1;
  
num2 = n2;
 
}
 
void displayResult()
 
{
  
cout << "Numbers are: " << num1 << " and " << num2 << "." << endl;
  
cout << "Addition is: " << add() << endl;
  
cout << "Subtraction is: " << subtract() << endl;
  
cout << "Product is: " << multiply() << endl;
  
cout << "Division is: " << divide() << endl;
 
}
 
T add() { return num1 + num2; }
 
T subtract() { return num1 - num2; }
 
T multiply() { return num1 * num2; }
 
T divide() { return num1 / num2; }
};
 
int main()
{
 
Calculator<int> intCalc(2, 1);
 
Calculator<float> floatCalc(2.4, 1.2);
 
cout << "Int results:" << endl;
 
intCalc.displayResult();
 
cout << endl << "Float results:" << endl;
 
floatCalc.displayResult();
 
return 0;
}
 
Outputs
 
Int results:
Numbers are: 2 and 1.
Addition is: 3
Subtraction is: 1
Product is: 2
Division is: 2
 
Float results:
Numbers are: 2.4 and 1.2.
Addition is: 3.6
Subtraction is: 1.2
Product is: 2.88
Division is: 2
 
4.4 . Object serialization
 
S
erialization
 consists of writing data
and 
objects
 on a support (a file, a buffer, a
socket), so that they can be reconstructed
later in the memory of the same or another
computing host.
 
The reconstruction process is also known as
deserialization.
 
4.5 . Type Conversion
 
A type cast is basically a conversion from one
type to another. There are two types of type
conversion:
Implicit Type Conversion
 Also known as
‘automatic type conversion’.
Done by the compiler on its own, without any external
trigger from the user.
Generally takes place when in an expression more
than one data type is present. In such condition type
conversion (type promotion) takes place to avoid lose
of data.
All the data types of the variables are upgraded to the
data type of the variable with largest data type.
 
4.5.1. Implicit Type Conversion
// An example of implicit conversion
 
#include <iostream.h>
 
int main()
{
 
int x = 10; // integer x
 
char y = 'a'; // character c
 
 
// y implicitly converted to int. ASCII
 
// value of 'a' is 97
 
x = x + y;
 
 
// x is implicitly converted to float
 
float z = x + 1.789;
 
 
cout << "x = " << x
  
<< "y = " << y
  
<< "z = " << z
 
 
return 0;
}
 
Output:
x = 107
y = a
z = 108.789001
4.5.2. Explicit Type Conversion
 
Explicit Type Conversion
: This process is also called
type casting and it is user-defined. Here the user can
typecast the result to make it of a particular data
type.In C++, it can be done by two ways:
 
Converting by assignment:
 This is done by explicitly
defining the required type in front of the expression in
parenthesis. This can be also considered as forceful
casting.
 
Syntax: (type) expression
Where ‘ type’ indicates the data type to which the final
result is converted.
 
4.5.2. Explicit Type Conversion
 
#include<iostream.h>
void main()
{
 
float x =90.765;
 
int y = (int) x;
 
cout << y;
}
 
4.6.Casting operators
 
A cast is a special operator that forces one data
type to be converted into another. As an
operator, a cast is unary and has the same
precedence as any other unary operator.
 
The most general cast supported by most of the
C++ compilers is as follows −
 
Syntax: (type) expression
Where type is the desired data type. There are
other casting operators supported by C++, they
are listed below
const_cast<type> (expr)
 − The const_cast operator is used to
explicitly override const and/or volatile in a cast. The target type
must be the same as the source type except for the alteration of its
const or volatile attributes. This type of casting manipulates the
const attribute of the passed object, either to be set or removed.
 
dynamic_cast<type> (expr)
 − The dynamic_cast performs a runtime
cast that verifies the validity of the cast. If the cast cannot be made,
the cast fails and the expression evaluates to null. A dynamic_cast
performs casts on polymorphic types and can cast a A* pointer into
a B* pointer only if the object being pointed to actually is a B
object.
 
reinterpret_cast<type> (expr)
 − The reinterpret_cast operator
changes a pointer to any other type of pointer. It also allows casting
from pointer to an integer type and vice versa.
 
static_cast<type> (expr)
 − The static_cast operator performs a
nonpolymorphic cast. For example, it can be used to cast a base
class pointer into a derived class pointer.
4.7. Dynamic casting
 
 
To use dynamic_cast<new_type>(ptr) the base class
should contain at least one virtual function.
 
dynamic casting
 is, primarily, used to 
safely
 downcast;
i.e., cast a base class pointer (or reference) to a derived
class pointer (or reference). It can also be used for
upcasting; i.e., casting a derived class pointer (or
reference) to a base class pointer (or reference).
 
Dynamic casting checks consistency at runtime; hence,
it is slower than static cast.
 
Take a look at the function signature of the dynamic
cast below:
#include <iostream.h>
 
 
class A
{
public:
 
virtual void f(){cout << "A::f()" }
};
 
class B : public A
{
public:
 
void f(){cout << "B::f()" }
};
 
int main()
{
 
A a;
 
B b;
 
a.f();        // A::f()
 
b.f();        // B::f()
 
 
A *pA = &a;
 
B *pB = &b;
 
pA->f();      // A::f()
 
pB->f();      // B::f()
 
pA = &b;
 
// pB = &a;      // not allowed
 
pB = dynamic_cast<B*>(&a;); // allowed but it returns NULL
 
 
return 0;
}
4.8.Dynamic Binding
 
 
C++
 provides facility to specify that the compiler
should match function calls with the correct
definition at the run time; this is called 
dynamic
binding
 or late 
binding
 or run-time 
binding
.
 
Dynamic binding
 is achieved using virtual
functions.
 
Base class pointer points to derived class object
 
4.9.RTTI (Run-time type Identification)
 
in C++, RTTI (Run-time type information) is a
mechanism that exposes information about an object’s
data type at runtime and is available only for the
classes which have at least one virtual function.
 
It allows the type of an object to be determined during
program execution
For example, dynamic_cast uses RTTI and following
program fails with error “cannot dynamic_cast `b’ (of type
`class B*’) to type `class D*’ (source type is not
polymorphic) ” because there is no virtual function in the
base class B
 
4.9.RTTI (Run-time type
Identification)
 
// CPP program to illustrate
// Run Time Type Identification
#include <iostream.h>
class B { };
class D: public B {};
 
int main()
{
 
B *b = new D;
 
D *d = dynamic_cast<D*>(b);
 
if(d != NULL)
  
cout<<"works";
 
else
  
cout<<"cannot cast B* to D*";
 
getch();
 
return 0;
}
 
Slide Note
Embed
Share

Dive into function templates and generic programming in C++, exploring how to create reusable code for multiple data types. Learn about generic function templates, class templates, and how to declare function templates efficiently. Enhance your understanding of type-independent patterns and how to implement them effectively in your projects.

  • C++
  • Generic Programming
  • Function Templates
  • Class Templates
  • Type-independent Patterns

Uploaded on Jul 16, 2024 | 1 Views


Download Presentation

Please find below an Image/Link to download the presentation.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. Download presentation by click this link. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.

E N D

Presentation Transcript


  1. 053 CS 45 OBJECT ORIENTED PROGRAMMING Degree 2ndSemester of second year By Dr. Prabakaran Narayanan Associate professor, CSISE DEPT

  2. TYPECASTING & DYNAMIC BINDING

  3. 3.1. Template Type-independent patterns that can work with multiple data types. Generic programming Code reusable Function Templates These define logic behind the algorithms that work for multiple data types. Class Templates These define generic class patterns into which specific data types can be plugged in to produce new classes.

  4. 4.2 Function and function templates C++ routines work on specific types. We often need to write different routines to perform the same operation on different data types. int maximum(int a, int b, int c) { int max = a; if (b > max) max = b; if (c > max) max = c; return max; } 4

  5. Function and function templates float maximum(float a, float b, float c) { float max = a; if (b > max) max = b; if (c > max) max = c; return max; } 5

  6. Function and function templates double maximum(double a, double b, double c) { double max = a; if (b > max) max = b; if (c > max) max = c; return max; } The logic is exactly the same, but the data type is different. Function templates allow the logic to be written once and used for all data types generic function. 6

  7. How to declare a function template? A function template starts with the keyword template followed by template parameter/s inside < > which is followed by function declaration. template <class T> T someFunction(T arg) { ... .. ... } In the above code, T is a template argument that accepts different data types (int, float), and class is a keyword. You can also use keyword typename instead of class in the above example. When, an argument of a data type is passed to someFunction( ), compiler generates a new version of someFunction() for the given data type.

  8. #include (iostream.h> Template < class T> T maximum(T a, T b, T c) { T max=a; if(b>max) if (c>max) return max; } Void main() { int x=30,y=67, z=8267; int x=maximum(x,y,z); //other data types double a=6.3, b=653.4, c=75.67; double sup= maximum(a,b,c); cout << The maximum number is << sup; } max=b; max=c

  9. template <typename T> void Swap(T &n1, T &n2) { Swapping of two numbers T temp; temp = n1; n1 = n2; n2 = temp; } int main() { int i1 = 1, i2 = 2; float f1 = 1.1, f2 = 2.2; char c1 = 'a', c2 = 'b'; cout << "Before passing data to function template.\n"; cout << "i1 = " << i1 << "\ni2 = " << i2; cout << "\nf1 = " << f1 << "\nf2 = " << f2; cout << "\nc1 = " << c1 << "\nc2 = " << c2; Swap(i1, i2); Swap(f1, f2); Swap(c1, c2); cout << "\n\nAfter passing data to function template.\n"; cout << "i1 = " << i1 << "\ni2 = " << i2; cout << "\nf1 = " << f1 << "\nf2 = " << f2; cout << "\nc1 = " << c1 << "\nc2 = " << c2; return 0; }

  10. 4.2. Generic Function Generic function to find a maximum value (see maximum example). template <class T> T maximum(T a, T b, T c) { T max = a; if (b > max) max = b; if (c > max) max = c; return max; } This function itself is incomplete because the compiler will need to know the actual type to generate code. So template program are often placed in .h or .cpp files to be included in program that uses the function. C++ compiler will then generate the real function based on the use of the function template. 10

  11. 4.2. Generic function Usage(cont..) After a function template is included (or defined), the function can be used by passing parameters of real types. Template <class T> T maximum(T a, T b, T c) int i1, i2, i3; Int m = maximum(i1, i2, i3); maximum(i1, i2, i3) will invoke the template function with T==int. The function returns a value of int type. 11

  12. Function Templates Usage Each call to maximum() on a different data type forces the compiler to generate a different function using the template. See the maximum example. One copy of code for many types. int i1, i2, i3; // invoke int version of maximum cout << "The maximum integer value is: " << maximum( i1, i2, i3 ); // demonstrate maximum with double values double d1, d2, d3; // invoke double version of maximum cout << "The maximum double value is: " << maximum( d1, d2, d3 ); 12

  13. 4.3 Class template So far the classes that we define use fix data types. Sometime is useful to allow storage in a class for different data types. See simplelist1 (a list of int type elements) example What if we want to make a simple list of double type? Copy paste the whole file and replace int with double Make use of typedef in C++, See simplelist2. Still need to change one line of code for a new type. 13

  14. Class template Function templates allow writing generic functions that work on many types. Same idea applies to defining generic classes that work with many types -- extract the type to be a template to make a generic classes. See simplelist 14

  15. How to declare a class template? template <class T> class className { ... .. ... public: T var; T someOperation(T arg); ... .. ... };

  16. Simple calculator using Class template // Program to add, subtract, multiply and divide two numbers using class template #include <iostream> template <class T> class Calculator { private: public: T num1, num2; Calculator(T n1, T n2) { } num1 = n1; num2 = n2; void displayResult() { } cout << "Numbers are: " << num1 << " and " << num2 << "." << endl; cout << "Addition is: " << add() << endl; cout << "Subtraction is: " << subtract() << endl; cout << "Product is: " << multiply() << endl; cout << "Division is: " << divide() << endl;

  17. T add() { return num1 + num2; } }; T subtract() { return num1 - num2; } T multiply() { return num1 * num2; } T divide() { return num1 / num2; } int main() { } Calculator<int> intCalc(2, 1); Calculator<float> floatCalc(2.4, 1.2); cout << "Int results:" << endl; intCalc.displayResult(); cout << endl << "Float results:" << endl; floatCalc.displayResult(); return 0;

  18. Outputs Int results: Numbers are: 2 and 1. Addition is: 3 Subtraction is: 1 Product is: 2 Division is: 2 Float results: Numbers are: 2.4 and 1.2. Addition is: 3.6 Subtraction is: 1.2 Product is: 2.88 Division is: 2

  19. 4.4 . Object serialization Serialization and objects on a support (a file, a buffer, a socket), so that they can be reconstructed later in the memory of the same or another computing host. consists of writing data The reconstruction process is also known as deserialization.

  20. 4.5 . Type Conversion A type cast is basically a conversion from one type to another. There are two types of type conversion: Implicit Type Conversion Also known as automatic type conversion . Done by the compiler on its own, without any external trigger from the user. Generally takes place when in an expression more than one data type is present. In such condition type conversion (type promotion) takes place to avoid lose of data. All the data types of the variables are upgraded to the data type of the variable with largest data type.

  21. 4.5.1. Implicit Type Conversion // An example of implicit conversion Output: x = 107 y = a z = 108.789001 #include <iostream.h> int main() { int x = 10; // integer x char y = 'a'; // character c // y implicitly converted to int. ASCII // value of 'a' is 97 x = x + y; // x is implicitly converted to float float z = x + 1.789; cout << "x = " << x << "y = " << y << "z = " << z } return 0;

  22. 4.5.2. Explicit Type Conversion Explicit Type Conversion: This process is also called type casting and it is user-defined. Here the user can typecast the result to make it of a particular data type.In C++, it can be done by two ways: Converting by assignment: This is done by explicitly defining the required type in front of the expression in parenthesis. This can be also considered as forceful casting. Syntax: (type) expression Where type indicates the data type to which the final result is converted.

  23. 4.5.2. Explicit Type Conversion #include<iostream.h> void main() { float x =90.765; int y = (int) x; cout << y; }

  24. 4.6.Casting operators A cast is a special operator that forces one data type to be converted into another. As an operator, a cast is unary and has the same precedence as any other unary operator. The most general cast supported by most of the C++ compilers is as follows Syntax: (type) expression Where type is the desired data type. There are other casting operators supported by C++, they are listed below

  25. const_cast<type> (expr) The const_cast operator is used to explicitly override const and/or volatile in a cast. The target type must be the same as the source type except for the alteration of its const or volatile attributes. This type of casting manipulates the const attribute of the passed object, either to be set or removed. dynamic_cast<type> (expr) The dynamic_cast performs a runtime cast that verifies the validity of the cast. If the cast cannot be made, the cast fails and the expression evaluates to null. A dynamic_cast performs casts on polymorphic types and can cast a A* pointer into a B* pointer only if the object being pointed to actually is a B object. reinterpret_cast<type> (expr) The reinterpret_cast operator changes a pointer to any other type of pointer. It also allows casting from pointer to an integer type and vice versa. static_cast<type> (expr) The static_cast operator performs a nonpolymorphic cast. For example, it can be used to cast a base class pointer into a derived class pointer.

  26. 4.7. Dynamic casting To use dynamic_cast<new_type>(ptr) the base class should contain at least one virtual function. dynamic casting is, primarily, used to safely downcast; i.e., cast a base class pointer (or reference) to a derived class pointer (or reference). It can also be used for upcasting; i.e., casting a derived class pointer (or reference) to a base class pointer (or reference). Dynamic casting checks consistency at runtime; hence, it is slower than static cast. Take a look at the function signature of the dynamic cast below:

  27. #include <iostream.h> class A { public: }; virtual void f(){cout << "A::f()" } class B : public A { public: }; void f(){cout << "B::f()" } int main() { A a; B b; a.f(); // A::f() b.f(); // B::f() A *pA = &a; B *pB = &b; pA->f(); // A::f() pB->f(); // B::f() pA = &b; // pB = &a; // not allowed pB = dynamic_cast<B*>(&a;); // allowed but it returns NULL } return 0;

  28. 4.8.Dynamic Binding C++ provides facility to specify that the compiler should match function calls with the correct definition at the run time; this is called dynamic binding or late binding or run-time binding. Dynamic binding is achieved using virtual functions. Base class pointer points to derived class object

  29. 4.9.RTTI (Run-time type Identification) in C++, RTTI (Run-time type information) is a mechanism that exposes information about an object s data type at runtime and is available only for the classes which have at least one virtual function. It allows the type of an object to be determined during program execution For example, dynamic_cast uses RTTI and following program fails with error cannot dynamic_cast `b (of type `class B* ) to type `class D* (source type is not polymorphic) because there is no virtual function in the base class B

  30. 4.9.RTTI (Run-time type Identification) // CPP program to illustrate // Run Time Type Identification #include <iostream.h> class B { }; class D: public B {}; int main() { } B *b = new D; D *d = dynamic_cast<D*>(b); if(d != NULL) cout<<"works"; else cout<<"cannot cast B* to D*"; getch(); return 0;

  31. THANK YOU

More Related Content

giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#