Как создать динамический массив абстрактного класса?
Допустим, у меня есть абстрактный класс 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++)), но я подумал, что это может быть уместно здесь, так как этот пост наиболее близок к мой вопрос, который я нашел при поиске.