вызов конструктора производного класса после dynamic_pointer_cast - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь реализовать фабрику символов, но не могу понять, как создать общий 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(...);

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

Спасибо за вашу помощь

1 Ответ

0 голосов
/ 13 сентября 2018

Вы не должны быть здесь. В вашей цепочке 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");
}
...