2013-02-28 2 views
1

Я искал, но не смог получить то, что хочу ...Передача структуры между функциями C++

Я делаю маленькую игру. И я получил этот struct, который содержит данные игрока.

struct Player 
{ 
    string name; 
    int level; 
    int exp; 
    int hp; // life 
    int mp; // mana 
    int shield; 
}; 

И когда в меню, пользователь выбирает, чтобы начать новую игру, он идет к этой функции:

int StartNewPlayer(string name) 
    { 
     Player player; 

     player.name = name; 
     player.level = 1; 
     player.exp = 0; 
     player.hp = 20; 
     player.mp = 5; 
     player.shield = 0; 

     *pass/return the struct here* 
    } 

Тогда у меня есть функция, которая выводит игровую доску, и где я должен использовать данные из нового игрока структуры, например:

void game_board() 
{ 
    cout << "Hello!" << player.name; 

    (...) 
} 

Наконец, где-то в main у меня есть:

int main() 
{ 
    StartNewPlayer(new_game()); 
    game_board(); 
} 

, который вызывает все функции выше.

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

ответ

3

Как насчет этого?

Player StartNewPlayer(string name) 
{ 
    Player player; 

    player.name = name; 
    player.level = 1; 
    player.exp = 0; 
    player.hp = 20; 
    player.mp = 5; 
    player.shield = 0; 

    return player; 
} 

void game_board(Player player) 
{ 
    cout << "Hello!" << player.name; 

    (...) 
} 

int main() 
{ 
    Player player = StartNewPlayer(new_game()); 
    game_board(player); 
} 
+0

Я получаю эту ошибку компиляции 'ошибка C2360: инициализация «Игрок» пропускается «case» label. Это потому, что игрок Player Player = StartNewPlayer (new_game()); game_board (player); 'находится в переключателе? –

+2

@HenriqueFerrolho Опубликовать код 'switch' будет полезен. Одно из решений заключается в том, чтобы окружить случай в фигурных скобках, как этот «случай 0: {Player player = ...; } break; ' – Pubby

+0

ALRIGHT! : D НАКОНЕЦ! это сделал трюк! не могли бы вы объяснить, почему? Я хотел бы понять ... А также, я сомневаюсь, в этой функции: 'Player StartNewPlayer (имя строки)' что означает 'Player'? это тип возврата? вроде как int? –

1

Не создавать дополнительные копии данных со сложными типами данных, используя передачу по значению

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

void StartNewPlayer(string name, Player *player) 
{ 
    player->name = name; 
    player->level = 1; 
    player->exp = 0; 
    player->hp = 20; 
    player->mp = 5; 
    player->shield = 0; 
} 

void game_board(Player* player) 
{ 
    cout << "Hello!" << player->name; 

    (...) 
} 

int main() 
{ 
    Player player; 
    StartNewPlayer(new_game(), &player); 
    game_board(&player); 
} 

Альтернатива с использованием передачи по ссылке:

Если вы поклонник ссылок, (который просто умный компилятор трюк, который делает использование указателей внутри снова):

void StartNewPlayer(string name, Player& player) 
{ 
    player.name = name; 
    player.level = 1; 
    player.exp = 0; 
    player.hp = 20; 
    player.mp = 5; 
    player.shield = 0; 
} 

void game_board(Player& player) 
{ 
    cout << "Hello!" << player.name; 

    (...) 
} 

int main() 
{ 
    Player player; 
    StartNewPlayer(new_game(), player); 
    game_board(player); 
} 
+0

+1 для получения информации о том, чтобы избежать создания конструкторов копий, -1 для того, чтобы сказать, что ссылки - всего лишь трюк компилятора, чтобы скрыть указатели. – Donnie

+0

@ Donnie - можете ли вы объяснить, что вы можете сделать, используя ссылки, которые невозможно достичь с помощью указателей? (ПРИМЕЧАНИЕ: не наоборот, т. Е. Я знаю, что ссылки имеют ограничения по сравнению с указателями). И если вы можете доказать мне, что ссылки генерируют другой ассемблерный код вместе по сравнению с указателями, я сниму свое заявление. – Tuxdude

+0

@Tuxdude Действительно, вы, вероятно, можете делать все со ссылками, которые вы можете с помощью указателей, так же, как вы можете делать все с помощью C, которые вы можете использовать с C++. Но C++ обладает определенными возможностями защиты от ошибок и удобочитаемости. – Alan

-1

Я бы предложил вернуть указатель на структуру игрока. Если вы вернете «ссылку», как вы делаете прямо сейчас, она вызовет конструктор копирования Player, который может привести к дальнейшим осложнениям.

Как правило, в конце StartNewPlayer (...) проигрыватель, который вы объявили там, перестанет существовать по мере того, как объем объекта закончится, поэтому при его возврате компилятор C++ получает то, что вы хотите сохранить объект живой и создаст для вас копию, невидимо. Если вы вернете указатель на него, вы действительно возвращаете объект, который вы выделили в своей функции.

Предположим, что у вас есть указатели в вашей структуре игрока, такие как

struct Player 
{ 
    int level; 
    char* name; //lets assume you did it like that 
} 

Когда вы возвращаете игрока, INT будет скопирован, но символ * не будет. ints легко обрабатываются, а char * нужны всевозможные сложные функции, такие как strlen и strncpy. Чем сложнее структура вашего игрока, тем больше проблем вы столкнетесь с помощью конструктора копии по умолчанию.

Другим решением было бы объявить конструктор копирования самостоятельно для структуры Player (действительно, вы могли бы использовать классы, поскольку они в основном взаимозаменяемы в C++).

Player(const Player& p) 
{ 
    name = p.name; 
    level = p.level; 
    // and so forth 
} 

Так что я хотел бы использовать

Player* StartNewPlayer(std::string name) 
{ 
    Player* player = new Player(); 
    player->name = name; 
    player->level = 1; 
    // snip 
    return player; 
} 

В конце вашей программы, убедитесь, что delete player иначе вы будете иметь утечку памяти