Lab 10.1: Creating Class and Function Templates
In this lab, you will use class and function templates to manage the data in a document file.Estimated time to complete this lab: 90 minutes
To complete the exercises in this lab, you must have the required software. For detailed information about the labs and setup for the labs, see Labs in this course.
Objectives
After completing this lab, you will be able to:
® Create class and function templates.
® Use CMap and CArray collection templates.
Prerequisites
Before working on this lab, you should be familiar with the following:
® CMap, CArray, and CList collection classes
Exercises
The following exercises provide practice with concepts and techniques covered in this chapter:
® Exercise 1: Creating a Class Template
In this exercise, you will create a header file for a class template.
® Exercise 2: Adding Collection Templates That Use CMap and CArray
In this exercise, you will use the class templates created in the first exercise to manage data in a document file.
® Exercise 3: Creating a Function Template
In this exercise, you will create a sorting function template.
The code that forms the basis for this exercise is in \Labs\Ch10\Lab01\Baseline. Copy these files to your working directory.
In this exercise, you will create a new header file named TCount.h and define a template named TCount. You will add one constructor and three member functions, GetContents, GetCount, and IncrementCount.
Start a new project
1. Copy the startup code in the baseline folder to your project folder.
2. Create a new header file in the project and name it TCount.h.
Add code to define the TCount template class
1. Add the statements that check to see whether the header file for TCount has been defined.
// TCount.h
#ifndef TCOUNT_H
#define TCOUNT_H
2. Define the TCount class template.
template <class T>
class TCount
{
3. Declare an integer member variable named m_count and a template variable, type T, named m_type.
int m_count;
T m_type;
4. Create a public section in the class. Define a constructor that takes template type T as a parameter. Initialize the m_type member variable to this parameter, and initialize the count to zero.
public:
TCount( T type) { m_type= type; m_count = 0;}
5. Define a public member function named GetCount that returns the integer variable m_count.
int GetCount() { return m_count; }
6. Define a public member function named GetContents that returns a reference to type T.
T& GetContents() { return m_type; }
7. Define a public member function named IncrementCount that increments the variable m_count.
int IncrementCount() { return ++m_count; }
8. Terminate the template definition and add the closing #endif statement.
};
#endif
9. Save TCount.h. The completed template class definition should look like the following example code:
// TCount.h
#ifndef TCOUNT_H
#define TCOUNT_H
class TCount
{
int m_count;
T m_type;
public:
TCount( T type) { m_type= type; m_count = 0;}
T& GetContents() { return m_type; }
int IncrementCount() { return ++m_count; }
};
The completed code for this exercise is in \Labs\Ch10\Lab01\Ex01.
Exercise 2: Adding Collection Templates That Use CMap and CArrayContinue with the files you created in Exercise 1, or if you do not have a starting point for this exercise, the code that forms the basis for this exercise is in \Labs\Ch10\Lab01\Ex01.
In this exercise, you will write the code that opens a document file, adds its contents to an array template, and prints the output to the screen.
Add a reference to the TCount class template file and CMap and CArray
1. Include header files at the top of CWrdDoc.h, just before the CWrdDoc class definition.
#include <afxtempl.h> // for the template collection classes
#include "tcount.h"
2. Add CWrdDoc::m_map and CWrdDoc::m_array. Add these manually to the CWrdDoc header file, as protected members.
CMap< CString, LPCSTR, TCount<CString>*, TCount<CString>* > m_map;
CArray< TCount<CString>*, TCount<CString>* > m_array;
Create a virtual function named DeleteContents that will delete any existing contents from CMap and CArray
This function uses the GetCount method of the TCount template as part of the code that locates and deletes any contents in CMap.
1. Right-click CWrdDoc in ClassView, and add DeleteContents as a virtual function.
2. Initialize an integer variable to hold the number of items in the map and set a position variable at the first item in the map.
int count = m_map.GetCount();
POSITION pos = m_map.GetStartPosition();
3. Iterate through the map and delete all the objects from the map.
for (int idx=0; idx<count; idx++) {
TCount<CString>* pStringObject;
m_map.GetNextAssoc( pos, dummyString, pStringObject );
delete pStringObject;
}
4. Delete all pointers from the array and the map.
m_map.RemoveAll();
m_array.RemoveAll();
5. The completed function should look like the following example code:
void CWrdDoc::DeleteContents()
{
// Retrieve the object pointers and delete objects
int count = m_map.GetCount();
POSITION pos = m_map.GetStartPosition();
for (int idx=0; idx<count; idx++) {
TCount<CString>* pStringObject;
m_map.GetNextAssoc( pos, dummyString, pStringObject );
delete pStringObject;
}
m_map.RemoveAll();
m_array.RemoveAll();
CDocument::DeleteContents();
}
Add code to handle the contents of CMap and CArray and open a document file
1. Add a call to DeleteContents as the first statement in CWrdDoc::Process.
bool CWrdDoc::Process(CStdioFile & file)
{
// Delete doc contents
DeleteContents();
//…
2. Complete CWrdDoc::Process by adding the following code to the innermost block. This code will take each word from the target file and determine if it exists in the CMap object. If it does not exist, the code will create a new entry in the CMap object for that word.
TCount<CString>* pStringObject;
if (!m_map.Lookup(strToken,pStringObject))
{
pStringObject = new TCount<CString>(strToken);
// add to map
m_map.SetAt(strToken, pStringObject);
// add to array
m_array.Add(pStringObject);
}
3. After the closing bracket, add code to increment the token count.
pStringObject->IncrementCount();
4. Complete CWrdDoc::OnFileOpen code by adding a call to CWrdDoc::Process. CWrdDoc::Process will take the file selected by the user and extract all of the words from that file. The complete handler is shown in the following example code:
void CWrdDoc::OnFileOpen()
{
CFileDialog dlg(TRUE);
if (dlg.DoModal() == IDOK)
{
CStdioFile file;
CFileException fe;
if (!file.Open(dlg.GetPathName(),CFile::modeRead,&fe))
{
fe.ReportError();
return;
}
SetTitle(file.GetFileName());
{
Process(file);
}
POSITION pos = GetFirstViewPosition();
CWrdView* pView = (CWrdView *) GetNextView(pos);
pView->Invalidate();
}
}
5. Modify CWrdDoc::GetSize so that it returns the number of items in CMap.
int CWrdDoc::GetSize()
{
return m_map.GetCount();
}
6. Replace CWrdDoc::draw code so that it uses TCount to display the contents of the CMap.
void CWrdDoc::draw(CDC * pDC, int SortType, int VerticalSpacing, int CharacterWidth)
{
// TODO:
// Add sorting code.
int count = GetSize();
for (int idx=0; idx<count; idx++)
{
// Instantiate a TCount template.
TCount<CString>* pStringObject;
pStringObject = m_array.GetAt(idx);
// The item name: CString& string = pStringObject->GetContents();
pDC->TextOut(5*CharacterWidth, idx*VerticalSpacing, string);
// The item count:
CString strCount;
strCount.Format("%d", pStringObject->GetCount());
pDC->TextOut(50*CharacterWidth,idx*VerticalSpacing, strCount);
}
}
The completed code for this exercise is in \Labs\Ch10\Lab01\Ex02.
In this exercise, you will add a function template for sorting the contents of an array. You will also add several sorting functions to the document object file.
Create the TQSort function template
1. Create a new header file, TQSort.h, and add the following code:
#ifndef TQSORT_H
#define TQSORT_H
// add code here.
#endif
2. Within the conditional statement, add a function template to swap two items of an array.
// Swap function template
template <class Type>
static void swap(Type* array, int i, int j)
{
Type temp = array[i];
array[i] = array[j];
array[j] = temp;
}
3. After the swap template, add the following:
// Quicksort template
// The comparison function will then determine how the comparison is done.
template <class Type>
void quicksort(Type* array, int loBound, int hiBound, int (*compfn)(Type,Type))
{
// stopping condition for recursion.
if (loBound >= hiBound)
return;
int lo = loBound;
int hi = hiBound + 1; // increment now for a later pre-decrement.
Type elem = array[loBound];
for (;;)
{
// Compare elements here.
while ((lo<hiBound) && (compfn(array[++lo],elem)<0)) {}
while ((hi>loBound) && (compfn(array[--hi],elem)>0)) {}
if (lo < hi)
swap(array, lo, hi);
else
break;
}
swap(array, loBound, hi);
quicksort(array, loBound, hi-1, compfn);
quicksort(array, hi+1, hiBound, compfn);
}
Add a reference to the TQSort function header file to the document object leader file
® Open the file WrdDoc.cpp. Include the TQSort.h file after the #include "WrdView.h" statement.
#include "TQSort.h"
Create compare functions in the document object header file
1. At the end of the WrdDoc.cpp file, add a compare function to sort by name.
int compareName( TCount<CString>* pStringObject1, TCount<CString>* pStringObject2)
{
CString& str1 = pStringObject1->GetContents();
CString& str2 = pStringObject2->GetContents();
return _stricmp(
str1.GetBuffer(str1.GetLength()) , str2.GetBuffer(str2.GetLength()) );
}
2. Add a compare function to sort by count.
int compareCount( TCount<CString>* pStringObject1, TCount<CString>* pStringObject2)
{
int int1 = pStringObject1->GetCount();
int int2 = pStringObject2->GetCount();
return (int1<int2) ? 1 : (int1==int2) ? 0 : -1;
}
3. Add DoSort as a public member function of CWrdDoc class.
void DoSort(int SortType);
void CWrdDoc::DoSort (int SortType)
{
if (SortType == SORT_BY_NOTHING)
return;
// Creating a pointer for the compare function, basing it upon sort type.
int (*comp)(TCount<CString>*, TCount<CString>* ) =
SortType==SORT_BY_COUNT ? compareCount :
compareName;
// sort the array.
quicksort(m_array.GetData(), 0, m_array.GetUpperBound(), comp);
}
5. Add a call to DoSort as the first call in CWrdDoc::Draw.
DoSort(SortType);
6. Build and run the application.
The completed code for this exercise is in \Labs\Ch10\Lab01\Ex03.
No comments:
Post a Comment