Objective:
To practice templates & copy constructors
Dynamic memory:
Till now, we have worked on program where all memory needs
were determined before program execution by defining the variables needed. But
there may be cases where the memory needs of a program can only be determined
during runtime. For example, when the memory needed depends on user input. On
these cases, programs need to dynamically allocate memory, for which the C++
language integrates the operators new
and delete
.
Operators new and new[]
Dynamic memory is allocated
using operator new
. new
is followed by a
data type specifier and, if a sequence of more than one element is required,
the number of these within brackets []
.
It returns a pointer to the beginning of the new block of memory allocated. Its
syntax is:
pointer = new type
pointer
= new type [number_of_elements]
The first expression is used to
allocate memory to contain one single element of type type
. The second one is used
to allocate a block (an array) of elements of type type
, where number_of_elements
is an
integer value representing the amount of these.
In this case, the system dynamically allocates space for five elements of
type int
and returns
a pointer to the first element of the sequence, which is assigned to foo
(a pointer). Therefore, foo
now points to a
valid block of memory with space for five elements of type int
.
Here, foo
is a pointer, and
thus, the first element pointed to by foo
can
be accessed either with the expression foo[0]
or
the expression *foo
(both
are equivalent). The second element can be accessed either with foo[1]
or *(foo+1)
, and so on...
There is a substantial
difference between declaring a normal array and allocating dynamic memory for a
block of memory using new
.
The most important difference is that the size of a regular array needs to be
a constant expression, and thus its size has to be determined at
the moment of designing the program, before it is run, whereas the dynamic
memory allocation performed by new
allows
to assign memory during runtime using any variable value as size.
Operators delete and delete[]
In most cases, memory allocated
dynamically is only needed during specific periods of time within a program;
once it is no longer needed, it can be freed so that the memory becomes
available again for other requests of dynamic memory. This is the purpose of
operator delete
, whose syntax
is:
" delete pointer;
delete[] pointer; "
The first statement releases the memory of a single element allocated
using new
, and the second
one releases the memory allocated for arrays of elements using new and a size
in brackets ([]
).
The value passed as argument to delete
shall
be either a pointer to a memory block previously allocated with new
, or a null
pointer (in the case of a null pointer, delete
produces no
effect).
Notice how the value within
brackets in the new statement is a variable value entered by the user (i
), not a constant
expression:
There always exists the possibility that the user introduces a value for i
so big that the system
cannot allocate enough memory for it. For example, when I tried to give a value
of 1 billion to the "How many numbers" question, my system could not
allocate that much memory for the program, and I got the text message we
prepared for this case (Error:
memory could not be allocated
).
It is considered good practice for programs to always be able to handle
failures to allocate memory, either by checking the pointer value (if nothrow
) or by catching the
proper exception.
Templates:
Generic Programming (one template->multiple data types)
There are two types of templates
·
Function
templates
·
Class
templates
Function Templates:
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.
The format for declaring function templates with type parameters is:
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.
For
example, to create a template function that returns the greater one of two
objects we could use:
|
template
<class myType> myType
GetMax (myType a, myType b) { return (a>b?a:b); } |
Here we have created a template function with myType as its template
parameter. This template parameter represents a type that has not yet been
specified, but that can be used in the template function as if it were a
regular type. As you can see, the function template GetMax returns
the greater of two parameters of this still-undefined type.
To use
this function template we use the following format for the function call:
function_name <type> (parameters);
For
example, to call GetMax to compare two integer values of
type int we can write:
|
int x,y; GetMax <int> (x,y); |
When the compiler encounters this call to a
template function, it uses the template to automatically generate a function
replacing each appearance of myType by the type passed as the actual
template parameter (int in this case) and then calls it. This process is
automatically performed by the compiler and is invisible to the programmer.
Class Templates:
We also
have the possibility to write class templates, so that a class can have members
that use template parameters as types. For example:
|
template <class T> class mypair { T values [2]; public: mypair (T first, T second) { values[0]=first; values[1]=second; } }; |
The class
that we have just defined serves to store two elements of any valid type. For
example, if we wanted to declare an object of this class to store two integer
values of type int with the values 115 and 36 we would write:
|
mypair<int> myobject (115, 36); |
this same
class would also be used to create an object to store any other type:
|
mypair<double> myfloats (3.0, 2.18); |
The only
member function in the previous class template has been defined inline within
the class declaration itself. In case that we define a function member outside
the declaration of the class template, we must always precede that definition
with the template <...> prefix.
Notice the
syntax of the definition of member function getmax:
|
template <class T> T
mypair<T>::getmax () |
Confused
by so many T's? There are three T's in this declaration: The first
one is the template parameter. The second Trefers to the type returned by
the function. And the third T (the one between angle brackets) is
also a requirement: It specifies that this function's template parameter is also
the class template parameter.
1.
Write
a program to convert kilogram to grams by passing pointers as arguments to the
function.
Provide:
·
default
constructor( )
·
void
setValue(intval) Points
the pointer to value
·
int
getValue() return
the value pointer is pointing to
·
float convert() to covert from kg to g (i-e input value passed
as parameter)
·
Destructor
()
·
void Display() to display the resultant
value
Your class should allocate memory
dynamically and there should be no memory leak and dangling pointer.
CODE:#include <iostream> using namespace std;
class ConV { private: float* Val; float conv=0;
public: ConV() { Val = new float; conv = 0;
} void setValue(float val) { *Val = val; }
float getValue() { return *Val; }
float convert() { conv=*Val*1000;
return conv; }
void Display() { cout << "\n\nThe
converted value in gram : " << convert(); }
~ConV() { delete Val; Val= NULL; }
};
int main() { float a = 0; ConV obj1; cout << "Enter
the value in Kilogram: "; cin >> a; obj1.setValue(a); obj1.Display();
} OUTPUT: |
2. Create a class to swap two characters. your class should contain data member that points to char type variable.
Provide: `
·
default
constructor( )
·
void
setValue(charmem1, charmem2) Points
the pointer to some value
·
char
getValue() return
the values repective pointer is pointing to
·
char
swapValue() to swap
the value of both the characters (i-e one
passed as parameter)
·
Destructor()
·
void Display() to display new and old
values
Your class should allocate memory
dynamically and there should be no memory leak and dangling pointer.
CODE:
#include <iostream> using namespace std;
class Swap { private: char *char1, *char2, temp;
public: Swap() { char1 = new char; char2 = new char; temp = NULL;
} void setValue(char mem1, char mem2) { *char1 = mem1; *char2 = mem2; }
char getValue() { return *char1; return *char2; }
char swapValue() { temp = *char1; *char1 = *char2; *char2 = temp; cout << "The
Swapped values : " << endl<<*char1 <<endl<< *char2; return 0; }
void Display() { cout << "The
Original values : " << endl << *char1 << endl << *char2<<endl; swapValue(); }
~Swap() { delete char1, char2; char1 = NULL; char2 = NULL;
}
};
int main() { char a = 'c'; char b = 'd'; Swap obj; obj.setValue(a,b); obj.Display(); } OUTPUT: |
No comments:
Post a Comment