template <class T> T averageArr(const T arr[], int len)
{
double sum=0;
for (int i = 0; i<len; i++)
sum = sum + arr[i];
return ((T)sum / len);
}
The general form of a template function is the reserve word template followed by list of formal type parameters inside the <>, followed by return type, identify and parameter list in parentheses. Note it is general practice not to prototype a template function. Templates sould be used when a function's algorithm does not change with different types. Overloading should be used when the function algorithm does vary with different types. Note that templates and overloading are not mutually exclusive. For example:
template <class T> void display(const T arr[], int size)
{
cout << arr[0];
for (int i =0; i<len; i++)
cout << ", " <<
arr[i];
cout << endl;
}
template <class T> void display(const T value)
{
cout << value << endl;
}
Note you can template multiple parameters in the following manner:
template <class T, class S> void display(const T value, const
S label)
{
cout << lablel << " " << value
<< endl;
}
int j=100;
int *jPtr;
// Point jPtr to j
jPtr = &j; // jPtr now contains j's address location
// To assign 200 to j
// Derference jPtr and set it equal to 200
*jPtr = 200;
Example Program:
#include <iostream>
using namespace std;
int
main()
{
int y=100;
int x=-20;
// Point yPtr to y
int *yPtr = &y;
cout << "Before modification of *yPtr." << endl;
cout << "&yPtr: " << &yPtr <<
" yPtr: " << yPtr << endl;
cout << "&y: " << &y <<
" y: " << y;
// Dereference
cout << " *yPtr: " << *yPtr <<
endl;
// Dereference yPtr and set it equal to 2112
*yPtr = 2112;
cout << endl << "After modification
of *yPtr." << endl;
cout << "&yPtr: " << &yPtr <<
" yPtr: " << yPtr << endl;
cout << "&y: " << &y <<
" y: " << y;
// Dereference yPtr
cout << " *yPtr: " << *yPtr <<
endl;
// Point yPtr to x
yPtr = &x;
cout << endl << "After modification
of yPtr." << endl;
cout << "&yPtr: " << &yPtr <<
" yPtr: " << yPtr << endl;
cout << "&x: " << &x <<
" x: " << x;
// Dereference yPtr
cout << " *yPtr: " << *yPtr <<
endl;
return 0;
}
Output from program:
Before modification of *yPtr.
&yPtr: 0012FF7C yPtr: 0012FF74
&y: 0012FF74 y: 100 *yPtr: 100
After modification of *yPtr.
&yPtr: 0012FF7C yPtr: 0012FF74
&y: 0012FF74 y: 2112 *yPtr: 2112
After modification of yPtr.
&yPtr: 0012FF7C yPtr: 0012FF78
&x: 0012FF78 x: -20 *yPtr: -20
Press any key to continue
Import compiler error message note must compiliers will from time to
time spit out the following message:
error C2166: l-value specifies const object or error <number>: l-value
.... lvalue stands for left hand value in other words a value
that can be assign to.
Dereferenced pointers are lvalues. The code which generated this error
is as follows:
const int i=0;
i = 100;
Allocating Memory off the Free Store (Heap)
Up to this point in the class all of the memory we have directly used has been gotton off the stack. C++/C allows us to allocate memory at run time by using Free Store (Heap). There are two commands that allow use to allocate memory from the free store malloc and delete. malloc is the old C style of allocating memory.
For example:
// C Style
int *aPtr = (int*)malloc(sizeof(char)); //
Note we must cast the void pointer returned by malloc to the approperate
type.
// C++ Style
int *aPtr = new int();
Once a developer is through using memory they must return to the free store, unless they want a memory leak in their code. Memory gotten with malloc must be freed with free and memory gotten with new deleted by delete.
For example:
free(aPtr);
delete aPtr;
With this new mechism a developer can now allocate arrays dynamiclly. The following code will allocate an array of n charactors.
#include <iostream>
using namespace std;
char* createCharArr(const int size)
{
char *array = new char[size];
memset(array, 0x00, size);
return array;
}
void main()
{
char *arr = createCharArr(6);
// Note c string "hello" is six charators long
// the compiler automatically puts an null terminator
on it
strcpy(arr, "hello");
cout << "Set iterator to the begining." << endl;
// Print out each individual char
char *iterator = &arr[0];
while (*iterator != '\0')
cout << *iterator++
<< endl;
cout << "Set iterator back to the begining." << endl;
// Set iterator back to begining
iterator = &arr[0];
do
{
cout << *iterator << endl;
} while (*++iterator != '\0');
delete [] arr;
}
Two expand on the pointer arithmatic above is an example of using pointers to display abitary arrays.
#include <iostream>
using namespace std;
template <class T> void Display(const T* begin, const T* end)
{
T* iter = (T*)begin;
while (iter != (end + 1))
cout << *iter++ <<
endl;
}
int main()
{
int intArr[5] = { 1, 2, 3, 4, 5};
int* iterator = &intArr[0];
for (int i = 0; i < 5; i++)
cout << *iterator++
<< endl;
cout << endl << "Using generic template
function to display int array data." << endl;
Display(&intArr[0], &intArr[4]);
cout << endl << "Using generic template
function to display C string array data." << endl;
char *strs[3] = { "One", "Two", "Three" };
Display(&strs[0], &strs[2]);
cout << endl << "Using generic template
function to display double array data." << endl;
double doubleArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8,
9, 1000.23 };
Display(&doubleArr[0], &doubleArr[9]);
return 0;
}
#include <iostream>
using namespace std;
enum EVENT_TYPE { BUTTON_PRESSED, BUTTON_ARMED };
struct GUIEvent
{
EVENT_TYPE Event;
char Msg[80];
};
#define CALLBACK bool(*)(const GUIEvent*, void *)
#define CALLBACKPTR(NAME1) bool(*NAME1)(const GUIEvent*, void *)
#define CALLBACK_PROTO(NAME) bool NAME(const GUIEvent* event, void*
user_data)
CALLBACKPTR(gButtonPressedCallback);
void* gButtonPressedUserData;
CALLBACKPTR(gButtonArmedCallback);
void* gButtonArmedUserData;
CALLBACK_PROTO(HandleButtonPressed);
CALLBACK_PROTO(HandleButtonArmed);
void AttachCallback(EVENT_TYPE type, CALLBACK, void*);
void DispatchLoop()
{
bool NotDoneProcessing=true;
char buf[80];
char ch;
GUIEvent event;
while (NotDoneProcessing)
{
cout << "Enter 'P'
for Button pressed. " << endl;
cout << "and 'A' for
Button armed. (X for quit) " << endl;
cin >> ch;
cin.getline(buf, 80);
cout.flush();
switch(ch)
{
case 'P' : event.Event
= BUTTON_PRESSED;
strcpy(event.Msg, "Button Pressed");
gButtonPressedCallback(&event, gButtonPressedUserData);
break;
case 'A' : event.Event
= BUTTON_ARMED;
strcpy(event.Msg, "Button Armed");
gButtonPressedCallback(&event, gButtonPressedUserData);
break;
case 'X' : NotDoneProcessing
= false;
break;
default :
cerr << "Illegal Value." << endl;
}
cout << endl;
}
}
int main()
{
char user_data[10] = "hello";
AttachCallback(BUTTON_PRESSED, &HandleButtonPressed,
(void*)user_data);
AttachCallback(BUTTON_ARMED, &HandleButtonArmed,
(void*)user_data);
DispatchLoop();
return 0;
}
CALLBACK_PROTO(HandleButtonPressed)
{
cout << "In HandleButtonPressed: " <<
endl;
cout << (char *)user_data
<< endl;
cout << event->Msg
<< endl;
return true;
}
CALLBACK_PROTO(HandleButtonArmed)
{
cout << "In HandleButtonArmed: " <<
endl;
cout << (char *)user_data
<< endl;
cout << event->Msg
<< endl;
return true;
}
void AttachCallback(EVENT_TYPE type, CALLBACKPTR(funcPtr), void* user_data)
{
switch (type)
{
case BUTTON_PRESSED :
gButtonPressedCallback =
funcPtr;
gButtonPressedUserData =
user_data;
break;
case BUTTON_ARMED :
gButtonArmedCallback = funcPtr;
gButtonArmedUserData = user_data;
break;
}
}