6
votes

Existe-t-il un moyen de déclarer des objets dans une instruction conditionnelle?

flowchart

J'ai du mal à comprendre comment créer correctement un objet en fonction du choix de l'utilisateur.

Dans le programme, je demande à l'utilisateur quelle classe il veut être - Chevalier ou Assistant. Je prends l'entrée «1» ou «2» pour représenter Knight et Wizard.

J'ai fait une déclaration de changement, et dans le cas 1, j'ai déclaré un objet Knight, et la même chose pour Wizard.

J'ai besoin d'utiliser ces objets en dehors de l'instruction switch, mais je ne peux pas. J'ai essayé de créer un objet "par défaut" en créant "Player player;" mais parce que la classe Player a une fonction purement virtuelle, je ne peux pas le faire non plus.

Comment puis-je faire cela efficacement?

Voici ce que j'ai jusqu'à présent: p>

int main()
{
std::string plyrName;
int input;
bool foo = false;

std::cout << "What is your name?\n";
std::cin >> plyrName;
std::cin.ignore(1000, '\n');

std::cout << "\nWelcome, " << plyrName << ". What class would you like to be?\n";
std::cout << "1. Knight.\n2. Wizard.\n";
std::cin >> input;

while (input != 1 && input != 2)
{
    if (foo == true)
        std::cout << "Please enter 1 for Knight and 2 for Wizard.\n";
    if (!(std::cin >> input))
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "\n";
        std::cout << "Only integers are allowed.\n";
    }
    else
        std::cout << "\n";
    foo = true;
}

switch (input)
{
case 1:
{
    Wizard player;
    break;
}
case 2:
{
    Knight player;
    break;
}
}


std::cout << "\nHere is your player information summary.\n";
std::cout << player.classType();

system("pause");
return 0;
}

J'ai besoin d'accéder à l'objet lecteur une fois qu'il a été créé, car je souhaite indiquer à l'utilisateur la classe qu'il a sélectionnée. Les deux classes Knight et Wizard ont une fonction pour afficher ceci.

EDIT: J'ai une question complémentaire. Dans le diagramme, Knight & Wizard ont une variable statique «nom d'attaque spéciale». Comment puis-je accéder à cette variable dans la fonction principale? La solution d'utiliser unique_ptr signifie que le pointeur pointera vers la classe de base Player, ne permettant ainsi pas l'accès aux membres de la classe dérivés tels que la variable statique «nom d'attaque spéciale». Dois-je avoir un défaut dans ma conception?


4 commentaires

Peut-être utiliser des pointeurs (de préférence pointeurs intelligents )? C'est ainsi que vous gérez généralement le polymorphisme en C ++.


vous avez besoin de pointeurs ou de références de toute façon si vous voulez utiliser le polymorphisme, peut-être corrigez-le d'abord, car répondre littéralement à votre question vous mènera au problème suivant


@ user463035818 Qu'entendez-vous par «résoudre ce problème d'abord» et répondre à cette question mènera au problème suivant? Comment résoudre ce problème si je souhaite utiliser le polymorphisme et éviter de créer un autre problème?


Je voulais dire que, on pourrait prendre votre question au pied de la lettre et écrire une "solution" qui crée soit un objet Knight soit un objet Wizard , mais cela ne vous aidera pas à les traiter tous les deux comme un Player sauf si vous utilisez des pointeurs ou des références. Notez que cela est déjà pris en compte par les réponses (enfin 2 sur 3 pour être précis;)


3 Réponses :


0
votes

Quelqu'un me corrige si je me trompe, mais les objets ne sont valides que dans le cadre de leur création, donc une fois que vous êtes sorti de cette instruction switch, ces objets ne sont plus accessibles.

Vous devez déclarer un objet de classe GAME OBJECT en dehors de l'instruction switch, puis créer soit l'assistant, soit le chevalier (car les deux classes héritent de GAME OBJECT).


3 commentaires

C'est vrai pour les variables locales, mais la mémoire (variables) obtenue avec un allocateur (en utilisant le mot-clé 'new') durera jusqu'à ce qu'elles soient libérées explicitement. Pour faciliter l'utilisation de ces variables allouées, la norme C ++ 11 a introduit des pointeurs intelligents.


Re: "corrigez-moi si je me trompe" - vous avez à moitié raison. Les objets nommés ont une portée de bloc; ils disparaissent à la fin du bloc dans lequel ils sont créés. Votre solution n'est pas tout à fait correcte. Vous devez créer un pointeur vers un GAME_OBJECT , créer un WIZARD ou KNIGHT et enregistrer son adresse dans ce pointeur. L'objet ne peut pas être un objet nommé, car alors il disparaîtrait. C'est pourquoi nous avons nouveau .


lire sur le "tranchage d'objet", ce que vous avez écrit est presque correct, cela ne fonctionnera pas avec les objets



6
votes

Dans votre cas, parce que vous voulez accomplir le polymorphisme, vous devriez aller chercher des pointeurs et des références. Pourquoi? Je recommande vivement cette belle réponse. Pourquoi le polymorphisme ne fonctionne-t-il pas sans pointeurs / références?

Alors, devriez-vous opter pour un pointeur brut, quelque chose comme Player * ?

Dans presque tous les scénarios, vous ne devriez jamais opter pour un pointeur brut et surtout, quand il pointe vers dynamique Mémoire. Simplement parce que toute erreur de programmation ou une exception peut conduire à ignorer delete .

Par conséquent, je vous recommande vivement d'opter pour des pointeurs intelligents introduits dans C ++ 11 comme unique_ptr et shared_ptr qui suivent le modèle RAII et garantissent la désinitialisation.

Voici un exemple d'utilisation de unique_ptr dans votre cas.

#include <memory>

using PlayerPtr = std::unique_ptr<Player>;
using KnightPtr = std::unique_ptr<Knight>;
using WizardPtr = std::unique_ptr<Wizard>;

int main()
{
    ...
    PlayerPtr playerPtr = nullptr;

    switch (input) {
        case 1: {
             playerPtr = KnightPtr(new Knight);
        }
        break;

        case 2: {
             playerPtr = WizardPtr(new Wizard);
        }
        break;
    }

    // use playerPtr outside.
}

Modifier:

Comme indiqué à juste titre par HTNW , vous devez choisir std :: make_unique au lieu d'utiliser new . Mais rappelez-vous, c'est un concept C ++ 14. Vous devez avoir le support du compilateur pour cela.


12 commentaires

Merci pour ça! Est-ce un moyen efficace de faire cela en général? Ou aurais-je dû faire cela dans une structure complètement différente si je venais de commencer à créer ces programmes?


Cette réponse serait meilleure si recommandait d'utiliser std :: make_unique sur new et expliquait pourquoi nous devons utiliser un pointeur du tout .


Je pense que vous devriez opter pour un modèle d'usine au lieu d'avoir un boîtier d'interrupteur. Cela vous aidera à long terme.


@HTNW J'ai essayé d'améliorer ma réponse. J'espère que ça a l'air beaucoup mieux que celui précédent.


@KunalPuri Parce que l'instruction switch n'est pas une implémentation réelle d'une usine?


@ Jean-BaptisteYunès Cela dépend de la manière dont vous l'implémentez. Je l'aurais implémenté en utilisant map au lieu d'un switch case.


@KunalPuri Qu'est-ce qu'une usine (dit de base)? Un morceau de code qui construit un objet polymorphe. Ensuite, ce commutateur fait exactement le travail, pas besoin de le rendre plus complexe pour OP en cours d'apprentissage ...


@ Jean-BaptisteYunès Je suis d'accord. C'est pourquoi j'ai dit à long terme. Les applications deviennent volumineuses presque instantanément et la maintenance devient alors un souci. Si les modèles de conception sont correctement incorporés dans la phase initiale, cela économise beaucoup de temps et d'efforts.


J'ai une question complémentaire si possible. Dans le diagramme, vous pouvez voir que Knight & Wizard a une variable statique «nom d'attaque spéciale». Comment puis-je accéder à cette variable dans la fonction principale? Le pointeur playerPtr ne peut pointer que sur les membres de la classe de base. Est-ce que j'ai un défaut dans ma conception?


@RaminAmiri Peut-être. J'aimerais vraiment savoir ce que vous essayez de faire.


J'ai téléchargé mon projet compressé dans Dropbox si vous êtes intéressé @KunalPuri dropbox. com / s / zgpwxt5v3bac30y / GAME1011_Lab1_AmiriRamin.zip? d‌ l = 0 J'ai toujours le problème.


@KunalPuri Désolé, j'ai le lien vers le mauvais projet. Voici le bon projet. dropbox.com/s/bsgbfmttlape6ve/…



1
votes

si vous créez votre variable dans la portée de la casse du commutateur, elle sera supprimée dès que vous quitterez cette portée vous menant à UB, vous la déclarez donc comme un pointeur afin qu'elle puisse survivre à l'instruction conditionnelle, c'est-à-dire: vous la déclarez comme base pointeur de classe avant & vous le donnez là où il pointe dans l'instruction conditionnelle

#include<memory>
int main()
{
std::string plyrName;
int input;
bool foo = false;
//create your player ptr
std::unique_ptr<Game_Object> player;
std::cout << "What is your name?\n";
std::cin >> plyrName;
std::cin.ignore(1000, '\n');

std::cout << "\nWelcome, " << plyrName << ". What class would you like to be?\n";
std::cout << "1. Knight.\n2. Wizard.\n";
std::cin >> input;

while (input != 1 && input != 2)
{
    if (foo == true)
        std::cout << "Please enter 1 for Knight and 2 for Wizard.\n";
    if (!(std::cin >> input))
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "\n";
        std::cout << "Only integers are allowed.\n";
    }
    else
        std::cout << "\n";
    foo = true;
}

switch (input)
{
case 1:
{   // initialize it  and it would work perfectly as you intend
    player = std::make_unique<WIZARD>();
    break;
}
case 2:
{   //****
    player = std::make_unique<KNIGHT>();
    break;
}
}


std::cout << "\nHere is your player information summary.\n";
std::cout << player->classType();

system("pause");
return 0;
}


1 commentaires

Veuillez expliquer votre solution plutôt que de simplement vider du code!