Online Book Reader

Home Category

Professional C__ - Marc Gregoire [338]

By Root 1310 0
copy constructor and operator= because of the compiler-generated versions. If you write templatized versions of the copy constructor and operator= and omit non-templatized versions, the compiler will not call these new templatized versions for assignments of grids with the same type. Instead, it will generate a copy constructor and operator= for creating and assigning two grids of the same type, which will not do what you want! Thus, you must keep the old non-templatized copy constructor and operator= as well.

Examine the new templatized copy constructor first:

template

Grid(const Grid& src);

You can see that there is another template declaration with a different typename, E (short for “element”). The class is templatized on one type, T, and the new copy constructor is also templatized on a different type, E. This twofold templatization allows you to copy grids of one type to another.

Here is the definition of the new copy constructor:

template

template

Grid::Grid(const Grid& src)

{

copyFrom(src);

}

Code snippet from MethodTemplates\Grid.h

As you can see, you must declare the class template line (with the T parameter) before the member template line (with the E parameter). You can’t combine them like this:

template // Incorrect for nested template constructor!

Grid::Grid(const Grid& src)

The copy constructor uses the protected copyFrom() method, so the class needs a templatized version of copyFrom() as well:

template

template

void Grid::copyFrom(const Grid& src)

{

mWidth = src.getWidth();

mHeight = src.getHeight();

mCells = new T* [mWidth];

for (size_t i = 0; i < mWidth; i++) {

mCells[i] = new T[mHeight];

}

for (size_t i = 0; i < mWidth; i++) {

for (size_t j = 0; j < mHeight; j++) {

mCells[i][j] = src.getElementAt(i, j);

}

}

}

Code snippet from MethodTemplates\Grid.h

In addition to the extra template parameter line before the copyFrom() method definition, note that you must use public accessor methods getWidth(), getHeight(), and getElementAt() to access the elements of src. That’s because the object you’re copying to is of type Grid, and the object you’re copying from is of type Grid. They will not be the same type, so you must use public methods.

The final templatized method is the assignment operator. Note that it takes a const Grid& but returns a Grid&:

template

template

Grid& Grid::operator=(const Grid& rhs)

{

// Free the old memory.

for (size_t i = 0; i < mWidth; i++) {

delete [] mCells[i];

}

delete [] mCells;

mCells = nullptr;

// Copy the new memory.

copyFrom(rhs);

return *this;

}

Code snippet from MethodTemplates\Grid.h

You do not need to check for self-assignment in the templatized assignment operator, because assignment of the same types still happens in the old, non-templatized, version of operator=, so there’s no way you can get self-assignment here.

Method Templates with Non-Type Parameters

In the earlier example with integer template parameters for HEIGHT and WIDTH, you see that a major problem is that the height and width become part of the types. This restriction prevents you from assigning a grid with one height and width to a grid with a different height and width. In some cases, however, it’s desirable to assign or copy a grid of one size to a grid of a different size. Instead of making the destination object a perfect clone of the source object, you would copy only those elements from the source array that fit in the destination array, padding the destination array with default values if the source array is smaller in either dimension. With method templates for the assignment operator and copy constructor, you can do exactly that, thus allow assignment and copying of different sized grids. Here is the class definition:

template

class Grid

{

public:

Grid() {}

template

Grid(const Grid

®Online Book Reader