Есть ли способ указать размер массива в базовом классе в унаследованном классе?

0

У меня есть абстрактный базовый класс, который содержит массив, а также два или более унаследованных класса, которые хотели бы иметь немного больший массив в базовом классе.

Я попытался решить эту проблему с помощью шаблонов:

template <int arraySize>
class Baseclass {
public:
    uint16_t arr[arraySize];
};

class InheritedClass :
    public Baseclass <5> {};

Проблема, с которой я сталкиваюсь сейчас: когда я использую указатель на некоторый объект Baseclass-Object, компилятор жалуется:

список аргументов для шаблона класса "Baseclass" отсутствует

Я думаю, что я понимаю, что здесь происходит: Baseclass без параметра шаблона теперь не полный, однако компилятор требует его.

Поэтому я задаюсь вопросом - есть ли (лучший) способ достичь того, что я пытаюсь сделать, не выделяя массив в InheritedClass и пропуская указатели до Baseclass?

Заранее спасибо!

  • 0
    Используйте вектор вместо массива.
  • 0
    Ваш код будет работать, но похоже, что вы пытаетесь использовать указатель на шаблон ( Baseclass* ) вместо указателя на базовый класс. Конечно, это не работает: шаблон не является типом .
Показать ещё 3 комментария
Теги:
templates
inheritance

5 ответов

1
Лучший ответ

Вы можете использовать Baseclass из класса, Baseclass от шаблона, и вместо этого использовать указатель.

3

Если массив непосредственно встроен в базовый класс, как в вашем примере, тогда невозможно указать размер этого массива. Точнее, изменение размера этого массива потребует создания совершенно другой версии этого базового класса для каждого конкретного размера массива. Это победит цель, так как ваше намерение, по-видимому, состоит в том, чтобы иметь единый общий базовый класс в иерархии. Это?

Это именно та проблема, с которой вы столкнулись с вашим шаблоном "решение". У вашей программы больше нет общего Baseclass. Вместо этого у вас есть Baseclass<5>, Baseclass<10> и т.д. - все совершенно разные независимые базовые классы. По-видимому, это не то, что вам нужно.

Единственный способ получить общий базовый класс с массивом размера времени выполнения в нем - это сохранить массив в базовом классе косвенно. Т.е. объявлять указатель uint16_t * в базовом классе и выделять необходимый объем памяти во время выполнения. Или вы можете просто использовать std::vector<uint16_t> вместо необработанного массива.

Обратите внимание: если вы решите пойти по указателю, не обязательно выделять память массива динамически. Вы можете просто сделать фактическую "память массива" членом производного класса, который уже "знает" конкретный размер

class Baseclass {
public:
  uint16_t *arr;
  size_t arraySize;

  Baseclass(uint16_t *arr, size_t arraySize) : arr(arr), arraySize(arraySize)
    {}
};

class InheritedClass : public Baseclass
{
  InheritedClass() : Baseclass(arr_memory, 5)
    {}
private:
  uint16_t arr_memory[5];
};

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

  • 0
    Автор вопроса отметил, что их требования ограничивают использование динамической памяти для массива в базовом классе!
  • 0
    Конечно, изменение размера создаст новый тип, к которому я и стремлюсь. Что я сделал сейчас, так это определил абстрактный базовый класс с виртуальными методами, который обращается к динамическому массиву. Таким образом, я работаю с базовым типом, в то время как во время выполнения для данного типа выбирается правильная реализация во время компиляции. Я забыл упомянуть: указатели тоже плохие, потому что класс сериализуется (копируется из одного места в другое), и указатели сломают это. Большое спасибо за ваш подробный ответ :)
Показать ещё 1 комментарий
0

Если вы явно указываете аргумент, C++ игнорирует выражение по умолчанию. Таким образом, в ваших производных классах вы указываете свои базовые потребности CRTP 'd base явно, но в базе вы также предоставляете расчет по умолчанию для использования (только) после создания экземпляра. Так:

#include <iostream>
// instantiation specifies size explicitly, default calculation ignored
// after instantiation names in default calculation are bound correctly

template<class d,int size=sizeof d::m2/sizeof *d::m2>
struct b {
        int m[size];
};

struct d: b<d,20> {
        double m2[20];
};

int main() {
        std::cout<<sizeof b<d>::m/sizeof *b<d>::m<<'\n';
}
0

В качестве взлома, который, вероятно, будет работать, baseclass метод в baseclass который reinterpret_cast this в baseclass<1>.

Это зависит от того, как ty0es компилируется в относительно разумные макеты: чтобы это произошло, убедитесь, что baseclass - это модуль или стандартная компоновка.

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

Обратная сторона? Насколько большой массив должен быть транспортирован параллельно, и вы лжете другим пользователям своего класса о размере массива времени выполнения. Плюс это чрезвычайно хрупкий: массив должен быть последним элементом baseclass.

Вероятно, вам лучше избавиться от статических ограничений времени компиляции и сохранить std::vector с границами времени выполнения, поскольку это позволит избежать неопределенных хаков поведения и уменьшить ложь на строку кода.

0
class Baseclass {
public:
    uint16_t *arr;
    Baseclass(int arrlen) {
        arr = new int[arrlen];
    }

    ~Baseclass() {
        delete arr;
    }

};

class InheritedClass :
    public Baseclass {
public:
    Inherited() : Baseclass(5){
    }
};

Если можно, вы можете просто использовать динамическое распределение.

  • 0
    Я не могу использовать динамическое размещение, поэтому я также не могу использовать std :: vector.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню