22.16 Resizable arrays


Suppose you want to have an array that holds, say, cCritter objects. There are really three options: maintain your own C-style array, use an array template from the ANSI C++ STL Standard Template Library, or use the Microsoft CArray template.

To maintain an array yourself means using a declaration like cCritter *_critter or cCritter _critter[] . (Note that C regards these two declarations as equivalent; in C an array is simply a pointer.) If you do this, you would also need an int _critter_count variable to keep track of the current number of points stored. And you'd either have to preallocate _critter to some generously large size (and worry about eventually writing off the end), or you'd have to keep reallocating the memory for the array as it grows.

That's a lot of work, and it's easy to make errors in doing it. Writing your own array code these days means reinventing the wheel. It's much better instead to use a presupplied array template. Here we have two choices: STL or MFC.

STL vector arrays

Every version of C++ comes with a platform-independent library of templates known as the STL or the Standard Template Library. This library was written at Hewlett-Packard around 1995 and is now part of the official ANSI C++ language standard, which means that all C++ compilers for every platform must support it. The STL library includes, among many other kinds of collection classes, an array template that's known as vector . The code for the STL template will normally be found in a file in your Visual Studio include directory; the name of this include file is, a bit oddly, just plain VECTOR , with no file extension. For whatever reason, Visual Studio needs a bit of a nudge to let the STL work; whenever you include an STL file you need to follow it with a code line of the form using namespace std; . To create an STL array of some class type T , you use the new type vector<T> .

Table 22.1. A Standard Template Library (STL) array template compared to an MFC array.

Template usage for

STL

MFC

Include instructions needed in file.

 #include <vector>  using namespace std; 

This include should appear only in the files where <vector> is used, and it should be the last include listed at the head of these files.

 #include <afxtempl.h> 

Prototype of array of classes.

 vector<cCritter> _critter; 
 CArray<cCritter,  cCritter &> _critter; 

Prototype of array of basic types.

 vector<int> _radius; 
 CArray<int, int>  _radius; 

Adding element to end of array.

 push_back(newpoint) 
 Add(newpoint) 

Deleting the array member in the i slot.

 erase(i) 
 RemoveAt(i) 

Accessing size of the array.

 size() 
 GetSize() 

Setting the array size.

 resize(newsize) 
 SetSize(newsize) 

Accessing an element for reading or setting.

 [i] 
 [i]  ElementAt(i)  GetAt(i), for read only 

One plus of STL templates is that they're portable to all C++ platforms, so you can expect to be able to use them in more environments. But there are some annoying gotchas associated with the now fairly old STL templates “ I won't go into them here. Certainly the Visual Studio documentation of the STL is not as easy to use as is their documentation of the CArray . And the CArray templates are tweaked so as to work smoothly with the MFC method of 'serializing' or saving and loading files. It's simpler to give in and do it the Microsoft way instead of trying to use STL. We're going to use the MFC CArray template in this book. Table 22.1 compares the template usage for STL arrays and MFC arrays.

MFC CArray arrays

The code for the CArray template is in a file called afxtempl.h . If you want to declare some CArray variables in a file, you need to add this line to the top of the file, so the compiler will know what we're talking about.

 #include <afxtempl.h> 

To create an array of objects of some type T , we normally declare our new type as

 CArray<T, T&>. 

The meaning of the second mention of T in the declaration is that this is the type used in some of CArray's internal functions that do things like add your elements to the CArray . The idea is that one normally uses the pass by reference for these types so as to marginally improve the speed of your code, by effectively passing pointers instead of copying whole structures. In the case where T is a primitive type like an int , we don't bother with the & for the second argument.

The default size of _critter in either case will be 0, and if you immediately try and execute a line that sets, say, _critter[1] to something, then your program will crash. Adding an element to an array will automatically grow it to a size large enough to hold the new element (i.e. it grows the size by one). But, if you are planning to read a lot of elements into your array using the [ ] operator, you need to set the array's size to be large enough before you start.

Another thing about array templates that it's important to be aware of is that when you add an element of type T to your array, it's a copy of your element which actually goes into the array rather than the element itself. So you need to be sure to have a good copy constructor and an overloaded =operator defined for any class of objects that you're going to put into an array template.

Actually we're going to be using a variation on the CArray template, and this is the CTypedPtrArray<CObArray, cMyClass *> template. This is used for holding an array of pointers to instances of some class we've written called cMyClass . For this to work, the cMyClass has to inherit from the MFC CObject class, which is a kind of universal base class in MFC. More on this below.



Software Engineering and Computer Games
Software Engineering and Computer Games
ISBN: B00406LVDU
EAN: N/A
Year: 2002
Pages: 272

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net