Подклассы с различными реализациями массива - PullRequest
0 голосов
/ 10 февраля 2011

Допустим, у меня есть шаблон базового класса MyBase:

template <class T>
class MyBase{
private:
    T data;
public:
    MyBase(T _data);
};

Я хочу подкласс этого дважды (по крайней мере сейчас):

  1. данные должны представлять собой динамический двумерный массив: T **data
  2. данные должны быть фиксированным двумерным массивом: T data[rows][cols]

Я все еще новичок в C ++ и не могу понять, как это сделать. В частности, я хочу сделать своего рода матричную библиотеку (прежде всего, в качестве учебного проекта). В прошлом я делал некоторые вещи, в которых динамическое хранение матрицы имело больше смысла, и наоборот. Таким образом, похоже, что хорошим решением было бы реализовать базовый класс, который предоставляет все общие функциональные возможности (например, insert(T item, int i, int j) должен использовать data[i][j] = item; в любом случае), затем создать подкласс DynamicMatrix и FixedMatrix. DynamicMatrix будет иметь конструктор, который сделал

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;
    }
}

И FixedMatrix просто:

for (i=0; i < rows; i++)
{
    for (j=0; j < cols; j++)
    {
         data[i][j] = 0;    
    }
}

Создать переменную-член T data; в базовом классе достаточно просто. Но затем в подклассах, как я могу преобразовать это в двойной указатель? Возможно, я не могу, я в порядке с этим. Но тогда что мне делать вместо этого?

1 Ответ

3 голосов
/ 10 февраля 2011

Здесь вы пытаетесь использовать наследование для повторного использования кода, что, на мой взгляд, не является хорошим подходом к дизайну;наследование - для свободы реализации, а композиция - для повторного использования кода.

В этом случае, если бы действительно было необходимо поддерживать эти разные случаи, я бы формализовал 2d-массив:

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;
};

Затем я бы предоставил реализации Array2D, которые вы указали:

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) {
           // ...
        }
        // ...
};

На этом этапе вы можете создать экземпляр Array2D, используя любой формат.Теперь любой код, который вы используете, может просто взять const Array2D& или Array2D&, где бы он ни имел дело с таким объектом.

Тем не менее, я думаю, что это, вероятно, ненужная сложность в том, что массив динамического размерабудет работать в любом случае, поэтому я просто согласился бы с этим, если не было веской причины поддерживать оба типа.

...