Professional C__ - Marc Gregoire [340]
virtual ~Grid();
Grid void setElementAt(size_t x, size_t y, const char* inElem); char* getElementAt(size_t x, size_t y) const; size_t getHeight() const { return mHeight; } size_t getWidth() const { return mWidth; } static const size_t kDefaultWidth = 10; static const size_t kDefaultHeight = 10; protected: void copyFrom(const Grid char*** mCells; size_t mWidth, mHeight; }; Code snippet from GridSpecialization\GridString.h Note that you don’t refer to any type variable, such as T, in the specialization: You work directly with char*s. One obvious question at this point is why this class is still a template. That is, what good is the following syntax? template <> class Grid This syntax tells the compiler that this class is a char* specialization of the Grid class. Suppose that you didn’t use that syntax and just tried to write this: class Grid The compiler wouldn’t let you do that because there is already a class named Grid (the original template class). Only by specializing it can you reuse the name. The main benefit of specializations is that they can be invisible to the user. When a user creates a Grid of ints or SpreadsheetCells, the compiler generates code from the original Grid template. When the user creates a Grid of char*s, the compiler uses the char* specialization. This can all be “behind the scenes.” Grid Grid string dummy = "dummy"; stringGrid1.setElementAt(0, 0, "hello"); stringGrid1.setElementAt(0, 1, dummy.c_str()); stringGrid1.setElementAt(1, 0, dummy.c_str()); stringGrid1.setElementAt(1, 1, "there"); Grid Code snippet from GridSpecialization\GridTest.cpp When you specialize a template, you don’t “inherit” any code: Specializations are not like subclasses. You must rewrite the entire implementation of the class. There is no requirement that you provide methods with the same names or behavior. In fact, you could write a completely different class with no relation to the original. Of course, that would abuse the template specialization ability, and you shouldn’t do it without good reason. Here are the implementations for the methods of the char* specialization. Unlike in the template definitions, you do not repeat the template<> syntax before each method or static member definition: Grid mWidth(inWidth), mHeight(inHeight) { mCells = new char** [mWidth]; for (size_t i = 0; i < mWidth; i++) { mCells[i] = new char* [mHeight]; for (size_t j = 0; j < mHeight; j++) { mCells[i][j] = nullptr; } } } Grid { copyFrom(src); } Grid { // Free the old memory. for (size_t i = 0; i < mWidth; i++) { for (size_t j = 0; j < mHeight; j++) { delete [] mCells[i][j]; } delete [] mCells[i]; } delete [] mCells; mCells = nullptr; } void Grid { mWidth = src.mWidth; mHeight = src.mHeight; mCells = new char** [mWidth]; for (size_t i = 0; i < mWidth; i++) { mCells[i] = new char* [mHeight]; } for (size_t i = 0; i < mWidth; i++) { for (size_t j = 0; j < mHeight; j++) { if (src.mCells[i][j] == nullptr) { mCells[i][j] = nullptr; } else { size_t len = strlen(src.mCells[i][j]) + 1; mCells[i][j] = new char[len]; strncpy(mCells[i][j], src.mCells[i][j], len); } } } } Grid { // Check for self-assignment. if (this == &rhs) { return *this; } // Free the old memory. for (size_t i = 0; i < mWidth; i++) { for (size_t j = 0; j < mHeight; j++) { delete [] mCells[i][j]; } delete [] mCells[i]; } delete [] mCells; mCells = nullptr; // Copy the new memory. copyFrom(rhs); return *this; } void Grid { delete [] mCells[x][y]; if (inElem == nullptr) { mCells[x][y] = nullptr; } else { size_t len = strlen(inElem)