Reputation: 2835
Let's say I have a base class template MyBase:
template <class T>
class MyBase{
private:
T data;
public:
MyBase(T _data);
};
I want to subclass this twice (at least for now):
T **data
T data[rows][cols]
I'm still a bit of a novice with C++, and I can't figure out how to do this.
Specifically, I want to make a sort of matrix library (primarily as a learning project). I've done some things in the past where having my matrix stored dynamically made more sense, and vice versa. So, it seems like a good solution would be to implement a base class that provides all the common functionality (insert(T item, int i, int j)
, for example, should use data[i][j] = item;
in either case), then subclass a DynamicMatrix and a FixedMatrix. The DynamicMatrix would have a constructor that did
data = new T*[rows];
for (int i = 0; i < rows; i++)
{
data[i] = new T[cols];
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
data[i][j] = 0;
}
}
And FixedMatrix just:
for (i=0; i < rows; i++)
{
for (j=0; j < cols; j++)
{
data[i][j] = 0;
}
}
Creating a member variable T data;
in the base class is easy enough. But then in the subclasses, how do I convert that to a double pointer? Perhaps I can't, I'm okay with that. But then what should I do instead?
Upvotes: 0
Views: 212
Reputation: 95509
Here you are trying to use inheritance for code reuse which, in my opinion, is not a good approach to design; inheritance is for freedom of implementation while composition is for code reuse.
In this case, if it were really necessary to support these different cases, I would formalize a 2d array:
template<typename T> class Array2D {
public:
virtual const T* operator[](int row_index) const = 0;
virtual T* operator[](int row_index) = 0;
virtual size_t rows() const = 0;
virtual size_t cols() const = 0;
};
Then I would provide the implementations of Array2D that you've specified:
template<typename T, int R, int C> class FixedArray2D : public Array2D {
public:
virtual const T* operator[](int row_index) const {
return &data_[row_index][0];
}
virtual T* operator[](int row_index) {
return &data_[row_index][0];
}
virtual size_t rows() const { return R; }
virtual size_t cols() const { return C; }
private:
T data_[R][C];
};
template<typename T> class DynamicArray2D : public Array2D {
public:
DynamicAray2D(int rows, int cols) {
// ...
}
// ...
};
At this point, you can instantiate an Array2D
using either format. Now whatever code you are using can simply take a const Array2D&
or an Array2D&
wherever it needs to deal with such an object.
That said, I think this is probably unnecessary complexity in that a dynamically sized array will work for either case, hence I would just go with that unless there were a compelling reason to support both types.
Upvotes: 3