Yep; just use templates:

Here's how this can be used:

#include "Fred.h" // *To get the definition for *`class Fred`
// *The code for *`Matrix<T>` is shown below...
void someFunction(Fred& fred);
void manipulateArray(unsigned nrows, unsigned ncols)
{
Matrix<Fred> matrix(nrows, ncols); // *Construct a *`Matrix<Fred>` called `matrix`
for (unsigned i = 0; i < nrows; ++i) {
for (unsigned j = 0; j < ncols; ++j) {
// *Here's the way you access the *`(i,j)` element:
someFunction( matrix(i,j) );
// *You can safely "return" without any special *`delete` code:
if (today == "Tuesday" && moon.isFull())
return; // *Quit early on Tuesdays when the moon is full*
}
}
// *No explicit *`delete` code at the end of the function either
}

Now it's easy to use

`Matrix<T>` for things other than

`Fred`. For
example, the following uses a

`Matrix` of

`std::string` (where

`std::string` is the standard string class):

#include <string>
void someFunction(std::string& s);
void manipulateArray(unsigned nrows, unsigned ncols)
{
Matrix<std::string> matrix(nrows, ncols); // *Construct a *`Matrix<std::string>`
for (unsigned i = 0; i < nrows; ++i) {
for (unsigned j = 0; j < ncols; ++j) {
// *Here's the way you access the *`(i,j)` element:
someFunction( matrix(i,j) );
// *You can safely "return" without any special *`delete` code:
if (today == "Tuesday" && moon.isFull())
return; // *Quit early on Tuesdays when the moon is full*
}
}
// *No explicit *`delete` code at the end of the function either
}

You can thus get an entire

*family* of classes from a

template. For example,

`Matrix<Fred>`,

`Matrix<std::string>`,

`Matrix< Matrix<std::string> >`, etc.

Here's one way that the template can be implemented:

template<typename T> // *See section on templates for more*
class Matrix {
public:
Matrix(unsigned nrows, unsigned ncols);
// *Throws a *`BadSize` object if either size is zero
class BadSize { };
// *Based on the Law Of The Big Three:*
~Matrix();
Matrix(const Matrix<T>& m);
Matrix<T>& operator= (const Matrix<T>& m);
// *Access methods to get the *`(i,j)` element:
T& operator() (unsigned i, unsigned j); *← subscript operators often come in pairs*
T const& operator() (unsigned i, unsigned j) const; *← subscript operators often come in pairs*
// *These throw a *`BoundsViolation` object if `i` or `j` is too big
class BoundsViolation { };
private:
unsigned nrows_, ncols_;
T* data_;
};
template<typename T>
inline T& Matrix<T>::operator() (unsigned row, unsigned col)
{
if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
return data_[row*ncols_ + col];
}
template<typename T>
inline T const& Matrix<T>::operator() (unsigned row, unsigned col) const
{
if (row >= nrows_ || col >= ncols_)
throw BoundsViolation();
return data_[row*ncols_ + col];
}
template<typename T>
inline Matrix<T>::Matrix(unsigned nrows, unsigned ncols)
: nrows_ (nrows)
, ncols_ (ncols)
//*, data_ <--initialized below (after the 'if/throw' statement)*
{
if (nrows == 0 || ncols == 0)
throw BadSize();
data_ = new T[nrows * ncols];
}
template<typename T>
inline Matrix<T>::~Matrix()
{
delete[] data_;
}