Вызвать конструктор производного класса после dynamic_pointer_cast

Я пытаюсь реализовать фабрику символов, но не могу понять, как создать общий shared_ptr для виртуального базового класса, а затем преобразовать его в производный класс с аргументами в конструкторе. В моем примере мой виртуальный базовый класс не может принимать аргументы в конструкторе, но они мне нужны в конструкторе производного класса.

std::shared_ptr<Character> CharacterFactory::createCharacter(Character::Type type, Character::SubType subtype, const TextureHolder &textures, sf::Vector2u windowSize) {

    std::shared_ptr<Character> character;

    if ( type == Character::enemy ) {
        std::dynamic_pointer_cast<Enemy>(character)(subType, textures, windowSize);

    } else if(type == Character::player) {
        //cast to player ...
    }

    return character;

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

character = new Enemy(...);

сработало бы. Все примеры, которые я нашел для литья, используют конструкторы по умолчанию.

Спасибо за помощь

std::make_shared<Enemy>(...)
DeiDei 13.09.2018 19:29

Конструкторы нельзя вызывать явно. Они безымянны, по ним нельзя взять адрес и нельзя вызывать функции. Они могут вызываться только неявно в процессе создания нового объекта. Кажется, что ваша конструкция попытается вместо этого вызвать operator().

François Andrieux 13.09.2018 19:37

@ FrançoisAndrieux: Я думаю, вы имели в виду, что не существует специального синтаксиса для вызова конструкторов. Их, безусловно, можно назвать явно. Только для случаев построения и преобразования по умолчанию они могут вызываться неявно. Однако я помню, как много лет обсуждал это с Джеймсом Канце. Он не был убежден, пока я не прокашлялся несколько цитат Бьярна Страуструпа.

Cheers and hth. - Alf 13.09.2018 19:58

@ Cheersandhth.-Alf Здесь может быть недоразумение. Я не имел в виду, что неявные вызовы конструкторов используются в неявных преобразованиях. Я имею в виду те вызовы, которые генерируются при создании нового экземпляра. Я также не считаю создание объекта явным вызовом конструктора (даже если конструктор будет вызываться). Мой комментарий должен был сказать, что нет способа вызвать конструктор, как функцию. Другими словами, создание объекта отличается от вызова конструктора объекта.

François Andrieux 13.09.2018 20:04

@ FrançoisAndrieux: T() вызывает конструктор по умолчанию T, создавая объект T. Для меня это «как функция». Это вызываемая функция, которая выглядит как вызов функции (хотя синтаксически я думаю, что это выражение преобразования типа, которое семантически не имеет смысла, но). Подводя итог, он похож на утку, крякает, как утка, и ковыляет, как утка.

Cheers and hth. - Alf 13.09.2018 20:07
1
5
282
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Тебе не следует проводить здесь кастинг. В вашей цепочке if-else вы создаете общий указатель на соответствующий тип, а затем возвращаете этот shared_ptr. Он будет автоматически преобразован в std::shared_ptr<Character>, как если бы у вас

Character * character = new Enemy(...);

Это означает, что ваша функция должна выглядеть примерно так

std::shared_ptr<Character> CharacterFactory::createCharacter(Character::Type type, Character::SubType subtype, const TextureHolder &textures, sf::Vector2u windowSize) {    
    if ( type == Character::enemy ) {
        return std::make_shared<Enemy>(subType, textures, windowSize);
    } else if(type == Character::player) {
        return std::make_shared<Player>(subType, textures, windowSize);
    } 
    return {}; // return null on bad type
}

Мы можем применить несколько настроек к вышеупомянутому, чтобы сделать его более производительным, а не просто молча возвращать нулевой указатель, если фабрике передан плохой type. Для этого мы воспользуемся std::unique_ptr и выдадим исключение, если получим плохой type. std_unique_ptr можно преобразовать в std::shared_ptr, так что это позволяет вашей фабрике по умолчанию работать с обоими типами интеллектуальных указателей. Это дает нам

std::unique_ptr<Character> CharacterFactory::createCharacter(Character::Type type, Character::SubType subtype, const TextureHolder &textures, sf::Vector2u windowSize) {    
    if ( type == Character::enemy ) {
        return std::make_unique<Enemy>(subType, textures, windowSize);
    } else if(type == Character::player) {
        return std::make_unique<Player>(subType, textures, windowSize);
    } 
    throw std::runtime_error("bad type passed to factory");
}

Другие вопросы по теме