2014-06-08 3 views
0

Я заранее извиняюсь за то, что являюсь новичком в OO-программировании.Как передать производный класс, если вы знаете только базовый класс?

У меня есть базовый класс Hero, с тремя производными классами Archer, Warrior и Mage. Пользователю предлагается выбрать один из них и создать объект соответствующего производного класса. Они имеют разные начальные значения и функции-члены, а следующий шаг - передать этот объект другой функции.

Предположим, что функция называется battle(), и она принимает объект в качестве аргумента. Как мне это сделать? Должен ли я создать три отдельных боя() или есть способ передать объект без необходимости определять производный класс?

void Hero::init(string job) 
{ 
    if (job == "archer") 
     Archer archer; 
    else if (job == "mage") 
     Mage mage; 
    else 
     Warrior warrior; 

    battle(); // What to put as argument? 
} 

ответ

3

battle() должен использовать ссылочный или (умный) указатель на базовый класс в качестве аргумента. Например:

void battle(std::shared_ptr<Hero> ptr); 

И ваш аргумент должен быть умным указателем, а также:

void Hero::init(const std::string& job) 
{ 
    std::shared_ptr<Hero> ptr; 

    if (job == "archer") 
     ptr = std::make_shared<Archer>(); 
    else if (job == "mage") 
     ptr = std::make_shared<Mage>(); 
    else 
     ptr = std::make_shared<Warrior>(); 

    battle(ptr); 
} 

std::shared_ptr является смарт-класс указателя, который инкапсулирует динамическое выделение памяти и приобретение ресурсов для указателя. Это так, что нам не нужно писать new где угодно. Более того, когда умный указатель уничтожается (это означает, что не существует больше копий ptr, если есть), то в содержащемся указателе Hero вызывается delete.

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

+0

std :: shared_ptr и std :: make_shared, похоже, не компилируются. Я использую последнюю версию Code Blocks. – geft

+1

@geft Вам нужно '# включить'' '' файл. – 0x499602D2

3

Нет, вы не должны создавать 3 различных battle функции, избегая именно цель наследования.

Вы можете создать одну battle функцию:

void battle(Hero& hero) 
{ 
} 

Вы можете назвать это следующим образом:

battle(archer); 
battle(mage); 
battle(warrior); 

, но вам нужно будет создать Heros по-другому, потому что, как они созданы теперь они выпадают из сферы действия, как только выполняются if или else.

+0

Спасибо, но что означает 'Hero &'? Я не знаком с этой концепцией. – geft

+1

Это ссылка. Это означает, что вы работаете с объектом, созданным вне функции боя. – alain

2

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

Hero* hero = new Archer(); 
Hero* hero = new Mage(); 
Hero* hero = new Warrior(); 

Тогда вы могли бы пройти базовый класс указатель Hero* к вашему методу battle

battle(hero) 

Подпись вашего метода будет:

void battle(Hero*) 

Этот м eans, метод боя может принять любого героя во время выполнения, будь то лучник, маг или воин.

+1

Это все еще создает экземпляры объектов производного класса. –

+0

Перефразировал предложение. – cppcoder

+0

@cppcoder Я немного смущен. Вы указываете указатель, чем указывает на динамически выделенный объект. Как это работает, когда указатель и объект имеют разные классы? – geft

Смежные вопросы