WedX - журнал о программировании и компьютерных науках

Использование массива в полиморфном дизайне

Я только начинаю по-настоящему разбираться в полиморфизме, но все же это новая для меня тема. Итак, вот моя проблема: у меня есть классы, враг и грабитель. Однако Bankrobber наследует от врага. Я попытался сделать массив из 10 Bankrobbers. Затем глобальная функция должна использовать все члены массива, чтобы что-то сделать, ну, я думаю, это бесполезное описание, поэтому вот код:

void UpdateEnemies(Enemy * p_Enemy, int counter) { 
    for(unsigned int i = 0;i < counter;i++) { 
        p_Enemy[i].Update(); 
    } 
}

int main(void) { 
    BankRobber EnemyArray[10]; 
    Enemy * p_Enemy = new BankRobber(13,1); 
    UpdateEnemies(EnemyArray,10); 
    system("PAUSE"); 
};   

Прошу прощения за языковые ошибки. я не носитель языка

Моя актуальная проблема: этот код предназначен только для практики, поэтому цель состоит в том, чтобы просто увидеть 10 раз обновление на консоли для каждого члена массива. Таким образом, функция UpdateEnemys должна вызывать все функции вражеского обновления. Метод с приведением типов не совсем то, что я хочу, потому что он больше не динамический, так как позже будет больше врагов. Не только Банкробберы.

04.09.2013

  • Мне очень жаль этот комментарий, но я не могу заставить выделение работать. 04.09.2013
  • void UpdateEnemies(Enemy * p_Enemy, int counter) { for(unsigned int i = 0;i ‹ counter;i++) { p_Enemy[i].Update(); } } int main(void) { BankRobber EnemyArray[10]; Враг * p_Enemy = новый BankRobber(13,1); ОбновлениеВрагов(ВражескийМассив,10); система(ПАУЗА); }; 04.09.2013
  • Я не уверен, что у вас за вопрос, но вы должны прочитать parashift.com/c++-faq/array-derived-vs-base.html. 04.09.2013
  • это просто для практики, я понимаю, что есть лучшие методы для реализации того, что я хочу делать. Просто код не работает, потому что пытается сослаться на что-то несуществующее 04.09.2013
  • Вы забыли объяснить, в чем именно заключается ваша проблема. Что этот код должен делать и что происходит вместо этого? 04.09.2013
  • Вы не можете обрабатывать массивы полиморфно. См. stackoverflow.com/questions/1411844/ 04.09.2013

Ответы:


1

Объявление массива BankRobber следующим образом

BankRobber EnemyArray[10];

Но чем обращаться к ним через указатель базового класса, как это

Enemy * p_Enemy;    
p_Enemy[i].Update();

Не сработает. Это связано с тем, что индексирование массива p_Enemy[i] будет выполняться с использованием смещения sizeof(Enemy)
Но sizeof(BankRobber), вероятно, больше, чем из sizeof(Enemy), поэтому p_Enemy[i] окажется не в том месте.

Вместо этого вы должны использовать вектор указателей, например

std::vector<Enemy*>

Таким образом, вы также можете использовать полиморфизм, если добавляете указатели на разные объекты в вектор. И вам не нужно передавать уродливые int counter

04.09.2013

2

Полиморфизм работает только с одиночными объектами, доступ к которым осуществляется по ссылке или указателю на базовый класс. Он не работает с массивом объектов: для доступа к элементам массива необходимо знать размер элемента, а это не так, если у вас есть указатель на базовый класс.

Вам понадобится дополнительный уровень косвенности: массив указателей на одиночные объекты, по строкам

void UpdateEnemies(Enemy ** p_Enemy, int counter) { 
    for(unsigned int i = 0;i < counter;i++) { 
        p_Enemy[i]->Update(); 
    } 
}

int main() {
    // An array of Enemy base-class pointers
    Enemy * EnemyArray[10]; 

    // Populate with pointers to concrete Enemy types
    for (unsigned i = 0; i < 9; ++i) {
         EnemyArray[i] = new BankRobber;
    }

    // Of course, the array can contain pointers to different Enemy types
    EnemyArray[9] = new Dragon;

    // The function can act polymorphically on these
    UpdateEnemies(EnemyArray,10);

    // Don't forget to delete them. Enemy must have a virtual destructor.
    for (unsigned i = 0; i < 10; ++i) {
         delete EnemyArray[i];
    }
}

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

04.09.2013

3

Вы так и не сказали, в чем именно проблема.

Вы пытались выполнить кастинг внутри своего кода? Что-то типа:

void UpdateEnemies(Enemy * p_Enemy, int counter) { 
    BankRobber *pRobber = (BankRobber*)p_Enemy;
    for(unsigned int i = 0;i < counter;i++) { 
        pRobber[i].Update(); 
    } 
}
04.09.2013
  • @Бен Хаймерс: Можете ли вы объяснить, почему это не сработает? (кроме комментария ОП, который я понимаю, когда он сказал, что у него могут быть и другие враги, кроме BankRobber - и в этом случае я понимаю). Я не мог понять, почему это не сработает из других ответов. 04.09.2013
  • Что ж, это сработает, если UpdateEnemies точно знает, что переданное p_Enemy указывает на массив BankRobber, но в целом это небезопасно :) Аналогично можно передать void* или intptr_t и привести к BankRobber; это так же противно. 04.09.2013
  • @Бен Хаймерс: Ну, я понимаю, но, по крайней мере, это работает. Я просто предложил это как возможное решение... 04.09.2013
  • Однако это не решение; ОП сказал, что хочет, чтобы он работал с другими подклассами Enemy. Ваш код выглядит для вызывающих так, как будто он работает с указателями на базу Enemy, но на самом деле ломается, если они на самом деле не являются BankRobber. Я не пытаюсь придираться или быть противным, это просто неправильно, извините! 04.09.2013
  • @Ben Hymers: OP сказал, что хочет, чтобы он работал с другими подклассами Enemy после того, как я опубликовал это решение ... 04.09.2013
  • Хорошо, но еще до редактирования заголовок вопроса относился к полиморфизму, который не отображается в вашем ответе. Возможно, вы избавились от нарушения прав доступа в фрагменте кода OP, но это просто исправление симптома основной причины, заключающейся в том, что массивы нельзя использовать полиморфно. Серьезно, это плохой ответ, я не понимаю, как вы можете его защищать. Извиняюсь, если кажусь спорящим анонимным интернет-человеком; Я просто пытаюсь помочь тебе понять, честное слово! 06.09.2013
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]