Как создать динамический массив абстрактного класса?

Допустим, у меня есть абстрактный класс Cat, у которого есть несколько конкретных подклассов Wildcat, Housecat и т.д.

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

Когда я пытаюсь динамически выделять массив Cat, он, похоже, не работает.

Cat* catArray = new Cat[200];

Ответ 1

Создав aray указателей на Cat, как в

 Cat** catArray = new Cat*[200];

Теперь вы можете поместить ваши экземпляры WildCat, HouseCat и т.д. в различные места в массиве, например

 catArray[0] = new WildCat();
 catArray[1] = new HouseCat();
 catArray[0]->catchMice(); 
 catArray[1]->catchMice();

Несколько предостережений, когда они сделаны
a) Не забудьте удалить экземпляры, выделенные в catArray, как в delete catArray [0] и т.д.
b) Не забудьте удалить сам catArray, используя

 delete [] catArray;

Вы также должны рассмотреть возможность использования вектора для автоматизации b) для вас

Ответ 2

Вам нужно будет создать массив указателей на Cat:

Cat** catArray = new Cat*[200];

Даже если базовый класс Cat был конкретным, вы все равно будете бегать в срез объектов, если вы создали массив Cat.

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

Ответ 3

Вы не можете округлить кошек в клетках фиксированного размера, потому что компилятор не знает, насколько велики будут кошки, и (сбой метафоры), как их инициализировать. Вам нужно будет сделать что-то вроде инициализации массива нулевыми кошачьими указателями или чем-то еще, а потом их ставить.

Ответ 4

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

Итак, это законно:

Housecat* theCats = new Housecat[200];

а затем вы можете получить доступ к каждой кошке через интерфейс Cat

bool catsMeow = ((Cat*)(&theCats[0]))->CanMeow();

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

Зачем? Поскольку у Cat будет абстрактный метод

bool CanMeow() = 0;

Чтобы все унаследованные кошки были реализованы. Затем вы можете спросить, может ли он мяукать, с вероятностью, что экземпляр Lion вернет false.

Ответ 5

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

Cat** catArray = new Cat*[200];
for(int i = 0; i < 200; i++){
   catArray[i] = nullptr;
}

for(int i = 0; i < 200; i++){
   if(catArray[i] != nullptr){
      AddRealCat(...);
      break;
   }
}      

Интересно, есть ли более простой способ сделать это, чтобы проверить, указывает ли элемент в массиве указателей на абстрактный класс на объект производного класса или является просто абстрактным указателем, не устанавливая для элемента значение nullptr. Например, есть ли в стандартной библиотеке какой-нибудь bool IsObject (ObjectType * ptr) или что-то в этом роде?

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

Я опубликовал это как самостоятельный вопрос (Массив указателей на абстрактный класс: на nullptr или не на nullptr (C++)), но я подумал, что это может быть уместно здесь, так как этот пост наиболее близок к мой вопрос, который я нашел при поиске.