Как получить доступ к указателю, сделанному внутри оператора if, вне его? - PullRequest
0 голосов
/ 08 января 2019

Я делаю простую программу для воспроизведения определенного боевого вызова в зависимости от выбранного пользователем покемона. У меня есть один основной класс (класс Pokemon) и два класса, которые наследуют виртуальную функцию battleRoar () от основного класса. Это код

#include <iostream>
using namespace std;

class Pokemon{
public:
    virtual void battleCall(){
    }
    virtual ~Pokemon() {}
};

class Weedle: public Pokemon{
public:
    Weedle(){
        cout << "Weedle Weedle!" << endl;
    }
    void battleCall(){
        cout << "-v- weedle" << endl;
    }
};

class Pikachu: public Pokemon{
public:
    Pikachu(){
        cout << "Pikaaaachu!" << endl;
    }
    void battleCall(){
        cout << "pikachu!!" << endl;
    }

};


int main(){

    cout << "Please pick a pokemon." << endl;
    cout << "1. Weedle" << endl;
    cout << "2. Pikachu" << endl;
    int a;
    cin >> a;
    if (a == 1){
        cout << "You picked a weedle!" << endl;
        Weedle chosenPoke;
        Pokemon *p1 = &chosenPoke;

    }
    else if (a == 2){
        cout << "You picked a pikachu!" << endl;
        Pikachu chosenPoke;
        Pokemon *p1 = &chosenPoke;
    } else { cout << "Invalid choice" << endl;}
    cout << "Would you like to hear your pokemon's battle call?" << endl;
    cout << "Yes or No" << endl;
    string choose;
    cin >> choose;
    p1->battleCall();       //produces error: use of undeclared identifier 'p1




    return 0;
}

Проблема, с которой я столкнулся, заключается в том, что указатели основного класса, указывающие на подкласс, больше не доступны за пределами условного выражения. В этом случае я знаю, что было бы просто вызвать рев в каждой условной ветви. Однако я хотел бы иметь возможность вызывать любой подкласс, созданный с помощью указателя, вместо создания вызова функции для каждого варианта условного выражения.

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Хотя основная проблема уже решена, вы можете столкнуться с проблемой при применении ответа. Указатель p1 не имеет допустимого значения, которое может вызвать ошибку сегментации.

Вы должны сделать что-то вроде этого:

std::unique_ptr<Pokemon> p1;

if (a == 1) {
    cout << "You picked a weedle!" << endl;
    p1 = std::make_unique<Weedle>();
} else if (a == 2){
    cout << "You picked a pikachu!" << endl;
    p1 = std::make_unique<Pikachu>();;
} else { cout << "Invalid choice" << endl;}

cout << "Would you like to hear your pokemon's battle call?" << endl;
cout << "Yes or No" << endl;
string choose;
cin >> choose;

// In case of invalid input, it'll work!!!
if (p1 != nullptr) {
    p1->battleCall();
}
0 голосов
/ 08 января 2019

Вы можете обнаружить, что, хотя main() еще не сложная функция, ее разбиение на более мелкую функцию позволяет более логически варьировать переменные.

, например

std::unique_ptr<Pokemon> 
create(int choice)
{
    std::unique_ptr<Pokemon> result;

    if (choice == 1)
    {
        std::cout << "You picked a weedle!" << std::endl;
        result = std::make_unique<Weedle>();
    }
    else if (choice == 2)
    {
        std::cout << "You picked a pikachu!" << std::endl;
        result = std::make_unique<Pikachu>();
    } 
    else 
    { 
        std::cout << "Invalid choice" << std::endl;
    }

    return result;
}

полный рабочий пример:

http://coliru.stacked -crooked.com / а / 8e20a47e0d5e1de5

0 голосов
/ 08 января 2019

Объявите указатель перед блоком if и измените создание объекта, который вы хотите вернуть.

Pokemon *p1;
if (a == 1){
        cout << "You picked a weedle!" << endl;
        /* Weedle chosenPoke;  -- don't construct the object on the stack */
        p1 = new Weedle();
}
...
p1->battleCall();
delete p1;
...

Это решает непосредственную проблему необъявленного идентификатора, но добавляет бремя, что вы должны удалить объект, когда он больше не требуется, или изменить свой код для использования умных указателей.

...