Просто, чтобы добавить немного к тому, что другие люди говорят ...
Одной из основных причин использовать абстрактные классы и виртуалов, так что вы можете иметь несколько типов объектов в одном массиве.
Вот пример из проекта я сделал в школе:
char buffer = '\0';
int itemindex = 0;
Item* myitem;//.................................. I used a polymorphic pointer Item
while (!myfile.get(buffer).fail()){//............ Check for failure each loop iteration
if (buffer == 'N' || buffer == 'P') {
if (_noOfItems - 1 >= itemindex) {//.... -1 because of index 0 and >= to account for the first set of entries
delete _items[itemindex];//.......... if it is >= than there has already been allocation at that index, so it must be freed
}//...................................... to avoid memory leak
if (buffer == 'P') {
myitem = new Perishable();//......... polymorphic pointer static type is now perishable (dynamic will always be item)
} else if (buffer == 'N') {//............... else is extra safe
myitem = new NonPerishable();//....... polymorphic pointer static type is now nonPerishable (dynamic is item)
}
myfile.ignore();//....................... ignore comma
myitem->load(myfile);
_items[itemindex] = myitem;//............ This line assigns myitem to the item index, since its polymorphic, only have to write
//............. it once, within the 'N' || 'P' scope.
itemindex++;//........................... This must incriment every time 'N' || 'P' is encountered, cause each represents an
}//.......................................... item entry.
}
То, что мы должны были сделать, это создать Скоропортящиеся и стойкие пункты. Если вы будете следовать комментариям, вы увидите, что я создал указатель Item (базовый класс), а затем на основе файла, который читается, если char является «P», я создаю объект скоропортящихся объектов (производный) или NonPerishable (также полученный) ,
Итак, суть здесь в том, что _items[itemindex] = myitem;
вызывается только один раз, а не в каждом состоянии отрасли buffer = P/N
Там же несколько интересных вещей происходит в этом примере, но, как я уже говорил, как скоропортящиеся (ребенок) и NonPerishable (child) находятся в массиве Item (parent).
Итак, если мы имеем дело с боссами (дочерними) и символами (дочерними), и они оба являются сущностями (родителями), вы можете прокручивать массив объектов (родительский), содержащий оба производных типа, и вызывать одну и ту же функцию. . что-то вроде этого.
for(int i = 0; i < entityList.length; i++){
entityList[i].attack
}
Теперь это/действительно/круто. Вы можете указать всем сущностям сделать одно и то же в одной строке, потому что они имеют один и тот же родительский тип.
Что вам действительно нужно знать, это то, о чем уже говорилось о динамической отправке. Способ, который мне был объяснен, прост: объект может иметь динамический тип и статический тип.
Динамический тип тип ссылки был создан, например:
Item* myitem //Dynamic type is Item
Статический тип является то, что указатель/в настоящее время/указывает. Так что теперь статический тип myitem также является типом Item.
Если я это сделать:
myitem = new NonPerishable();
указатель myitem теперь указывает на тип ребенка 'стойкому'. Динамический тип не изменяется, поскольку он был создан как Item. Таким образом, динамический тип есть/still/type Item. Статический тип, однако, теперь NonPerishable, потому что указатель Item (myitem) теперь указывает на объект NonPerishable.
Примечание: Dynamic является то, что она была создана, как (это может быть контрпродуктивным интуитивное именем, но это так)
Наконец, если у вас есть родительский класс и класс ребенка, что оба имеют функцию с одно и то же имя, но различная реализация, вы либо получите раннее связывание, либо позднее привязку (также называемую динамической отправкой).
Раннее связывание означает, что функция, которая срабатывает, будет родительской функцией, динамическая отправка означает, что функция, которая срабатывает, будет дочерней. Раннее связывание по умолчанию для C++, для получения динамической отправки вы должны объявить эту функцию как «виртуальную», тогда по умолчанию будет дочерняя функция.
Одним из способов переопределения привязки является явное объявление пространства имен. Вот пример:
class Parent; //pseudo code
class Child : public Parent
object.Child::myfunction()
Примечание: Обычно, если родитель и ребенок имеют ту же функцию (MyFunction) будет раннее связывание (родительская версия). В этом случае вы используете пространство имен child ::, чтобы оно вызывало дочернюю версию myfunction.
Это много информации, если у вас есть какие-либо вопросы, которые я могу разработать.
Возможный дубликат [Почему я должен использовать указатель, а не сам объект?] (Http://stackoverflow.com/questions/22146094/why-should-i-use-a-pointer-rather- чем сам объект) –
Сделайте себе одолжение и найдите другую книгу, чтобы изучить программирование на С ++. В этом примере кода есть много ошибок, которые вам просто нужно будет отучить. Подобно 'using namespace std;', те 'int *' ', которые указывают на один 'int' (возможно, только что использовали' int'), присваивая '0' указателю непосредственно перед его удалением (пустая трата времени); все эти бесцельно защищенные члены. –
Я вижу вашу мысль, и я читаю и другие книги. Я действительно не понимаю, почему присвоение 0 указателю. Я думаю, что эта книга объясняет некоторые понятия (например, классы, векторы, указатели и ссылки) лучше других. Я тоже читал Прату, но он настолько детализирован во многих местах, и вроде бы теряет фокус от основного предмета. – Sabyc90