Variable or field play declared void

0

Witam. Od dwóch godzin próbuję zrozumieć na czym polega problem, ale już powoli dostaję siwych włosów. Błagam, niech mi ktoś powie gdzie jest błąd. Dodam że jak nie dzielę programu na pliki to wszystko działa ok.
Log kompilacji:

Kompilator: Default compiler
Building Makefile: "D:\Tomek\studia\Semestr drugi\Informatyka\Programy\Gra RPG\Makefile.win"
Wykonywanie make...
make.exe -f "D:\Tomek\studia\Semestr drugi\Informatyka\Programy\Gra RPG\Makefile.win" all
g++.exe -c gamestep.cpp -o gamestep.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include"

In file included from heroe.h:3,
from gamestep.cpp:4:
gamestep.h:9: error: variable or field play' declared void gamestep.h:9: error: expected ;' before '(' token

gamestep.cpp:11: error: no void Start::play(Heroe)' member function declared in class Start'

make.exe: *** [gamestep.o] Error 1

Wykonanie zakończone
Plik main:

#include <iostream>
#include <string.h>
#include "gamestep.h"
#include "heroe.h"
using namespace std;


int main()
{
    Heroe nowy;
    Start nowa;
    nowa.play(nowy);
    getchar();
    return 0;
}

plik heroe.h

#ifndef heroe_h
#define heroe_h
#include "gamestep.h"
#include <list>
#include <string.h>

using namespace std;

class Heroe{
      private:
              string imie;
              
              int runy, hp, zrecznosc, sila;
      public:
             Heroe(){};
             ~Heroe(){};
             string getImie(){return imie;}
             int getHp(){return hp;}
             int getRuny(){return runy;}
             int getZrecznosc(){return zrecznosc;}
             int getSila(){return sila;}
             void setImie(string _imie){imie = _imie;}
             void setHp(int _hp){hp = _hp;}
             void setRuny(int _runy){runy = _runy;}
             void setSila(int _sila){sila = _sila;}
             void setZrecznosc(int _zrecznosc){zrecznosc = _zrecznosc;};
};

#endif

gamestep.h

#ifndef gamestep_h
#define gamestep_h
#include "heroe.h"
#include <list>
#include <string.h>

class Start{
      public:
             void play(Heroe &);
             
};

gamestep.cpp

#include <iostream>
#include <string.h>
#include <ctime>
#include "heroe.h"
#include "gamestep.h"


using namespace std;

void Start::play(Heroe &m)
{
string _imie;
cout << "Podaj imie swojego bohatera" << endl;
cin >> _imie;
m.setImie(_imie);
srand(static_cast<int>(time(NULL))); 
m.setSila(rand() % 10);
m.setHp((rand() % 100)+5);
m.setZrecznosc(rand() % 10);
}
0
  1. <string> to nie to samo co <string.h>!
  2. Tragicznie dodajesz nagłówki
  3. Brak #endif w gamestep.h

Poza tym wszystko jest ok. Może to winda Deva? Bo Code::Blocks nie robi problemów, a ma troche nowszy kompilator...

0

Dzięki za odpowiedź. Już sobie jakoś poradziłem. Teraz mam jeszcze jedno pytanie. Pisany program to tekstowa gra Rpg. Program ma kończyć działanie gdy bohater będzie miał o hp. W głównym pliku mam pętle
Heroe nowy;
GameStep *gra;
Start gra1;
gra= &gra1;
while( nowy.getHp() > 0)
{
gra->play(nowy);
gra = gra->getNext();
}


Natomiast plik gamestep.h to :

class GameStep{
public:
virtual void play(Heroe&) = 0;
virtual GameStep* getNext() = 0;
};

class Start: public GameStep{
public:
void play(Heroe&);
GameStep* getNext();
};

class Battle: public GameStep{
protected:
int hp, sila, zrecznosc;
public:
~Battle(){};
void play(Heroe&);
GameStep* getNext();
};

class Riddle: public GameStep{
public:
void play(Heroe&);
GameStep* getNext();
};

Jak za pomocą tych zwracanych wskaźników uruchamiać kolejne metody play, bo powyższy program dział tylko wtedy gdy zwracam referencję, a nie wskaźnik.
0

Nie rozumiem pytania. Możesz przecież przyjmować wskaźniki zamiast referencji do tych metod.
Poza tym mam wrażenie że tragicznie to zaprojektowałeś...

0

Hmm. Co do zaprojektowania, to ten schemat z pliku gamestep jest narzucony przez prowadzącego zajęcia...
Wracając do tego co chcę osiągnąć. Metoda gamestep w klasie Battle wygląda następująco:

GameStep* Battle::getNext()
{  
    Riddle *gra1;
    return gra1;
}

jak za pomocą wskaźnika gra1, uruchomić metodę play w klasie Riddle? Gdy za pomocą metody getNext() zwracam referencję robię to w sposób gra1->play(nowy), ale jakuruchomić tą metodę mając wskaźnik, zamiast referencji? Może to jakieś chwilowe zaćmienie, ale siedzę nad tym programem już dobre 8 godzin i naprawdę mam już dość.
Shalom-> Tak btw, to chyba jesteśmy z tego samego wydziału, bo kojarzę Cię z forum miasteczka.

0

Coś chyba pomieszałeś. Operatorem wywoływania metod / odnoszenia sie do pól klasy dla obiektu / referencji jest kropka, tzn

Typ obiekt;
obiekt.metoda();

A dla wskaźników strzałka

Typ* wskaznik = new Obiekt();
wskaznik->metoda();

Strzałke równie dobrze możesz zapisać tak:

(*wskaznik).metoda();

Nie ma innych opcji.
Mylisz referencję ze wskaźnikiem. Wiem nawet dlaczego. Bo operator & ma dwa znaczenia, w zależności od kontekstu użycia (uroki języków silnie kontekstowych jak C++).

Typ obiekt;
Typ* wskaznik = &obiekt; //pobieram za pomocą & ADRES pamięci pod którą znajduje się obiekt i przypisuje do wskaźnika wskaznik
Typ& referencja = obiekt; //przypisanie REFERENCJI do obiektu obiekt

Więc jeszcze raz: sprecyzuj problem -> pokaż jaki kawałek kodu ci nie działa ;]

@Toma to są uroki posiadania ładnego i rzadkiego avatara, identycznego na każdym forum na którym sie udzielam ;)

0

Dobra, spróbuje jeszcze raz wyjaśnić o co mi chodzi. Mianowicie:
Mój main wygląda mniej więcej tak:

    Heroe nowy;
    GameStep *gra;
    Start gra1;
    gra = &gra1;
    while( nowy.getHp() > 0)
    { 
    gra->play(nowy);
    gra = gra->getNext();
    }

Najpierw wywołuję metodę play z klasy Start, a potem metodę play z innych klas, w zależności od tego co wybrał użytkownik.
Gdy mam metodę getNext() zadeklarowaną jako:

GameStep* (tutaj nazwa klasy)::getNext()
{
  Battle(przykładowo) gra1;
  return &gra1;
}

to wszystko działa dobrze, tylko od kompilatora dostaję warningi:

gamestep.cpp: In member function virtual GameStep* Start::getNext()': gamestep.cpp:30: warning: address of local variable gra1' returned

gamestep.cpp: In member function virtual GameStep* Battle::getNext()': gamestep.cpp:72: warning: address of local variable gra1' returned

gamestep.cpp: In member function virtual GameStep* Riddle::getNext()': gamestep.cpp:194: warning: address of local variable gra1' returned

jak przerobić ten program żeby tych ostrzeżeń nie otrzymywać, jednocześnie zostawiając nagłówek funkcji taki jak jest teraz?
Jeszcze takie pytanie poboczne. Mam polecenie :

Travel - po wywołaniu play na bohaterze, powinno pojawić się pytanie, czy chce wyruszyć w niespokojne okolice, gdzie czeka go walka, czy też woli podróżować po bezpiecznej drodze. W zależności od wyboru, metoda getNext zwracać będzie albo Fate - gdy wybierze podróż, albo Battle gdy wybierze walkę.
Skąd metoda getNext ma wiedzieć, co wybrałem w metodzie play, skoro nic do niej nie przekazuję? Mam nadzieję że teraz w miarę jasno to wytłumaczyłem. Z góry dzięki za pomoc.

0

@Shalom

To przecież Kakashi Mangekyou Sharingan i nie uważasz, że jest wielu fanów naruto w sieci ;p ?

0
  1. Tyś słyszał o ZMIENNYCH LOKALNYCH? One ZNIKAJĄ po wywołaniu funkcji / po wyjsciu z bloku. NIE WOLNO ich zwracać poza funkcję. Wskaźniki są do zabawy DYNAMICZNIE przydzielaną pamięcią! Zapomnij w ogole że za pomocą &zmienna można pobrać jej adres. Naucz się korzystać z new i new[] (oraz delete i delete[])
  2. Jak to skąd będzie wiedzieć? Musisz to gdzieś w bohaterze zapisać jako pole, a potem odczytywać to pole i zwracać co ma zwracać.
  3. Musisz zrozumieć co to jest polimorfizm. Twój program ma sie na nim opierać, co widać na pierwszy rzut oka. Ale ty pojęcia nie masz jak to działa. Jeśli masz klasy
    dziedziczące z pewnej bazy w której masz metodę wirtualną to program sam sobie rozpozna z której klasy ma ją wołać.
#include <iostream>
using namespace std;

class Bohater
  {
  private:
    bool niebezpieczny;
  public:
    void play()
    {
      cout<<"Niebezpieczny? 0 lub 1\n";
      cin>>niebezpieczny;
    }
    bool getNiebezpieczny()
    {
      return niebezpieczny;
    }
  };

class Krok
  {
  protected:
    bool niebezpieczny;
  public:
    virtual void play(Bohater&)=0;
    virtual Krok* nastepny()=0;
  };

class Niebezpieczny : public Krok
  {
    virtual void play(Bohater& ala);
    virtual Krok* nastepny();
  };

class Bezpieczny : public Krok
  {
    virtual void play(Bohater& ala);
    virtual Krok* nastepny();
  };

void Niebezpieczny::play(Bohater& ala)
{
  cout<<"Niebezpieczny!\n";
  niebezpieczny = ala.getNiebezpieczny();
}
Krok* Niebezpieczny::nastepny()
{
  if (niebezpieczny)
    return new Niebezpieczny();
  else
    return new Bezpieczny();
}

void Bezpieczny::play(Bohater& ala)
{
  cout<<"Bezpieczny!\n";
  niebezpieczny = ala.getNiebezpieczny();
}
Krok* Bezpieczny::nastepny()
{
  if (niebezpieczny)
    return new Niebezpieczny();
  else
    return new Bezpieczny();
}


int main()
{
  Bohater ala;
  ala.play();
  Krok* gra = new Bezpieczny(); //nie chce mi sie robic twojej klasy Start wiec zacznę od Bezpieczny :P
  Krok* poprzedni;
  gra->play(ala); //zawsze da nam Bezpieczny! bo od tego zaczynamy
  poprzedni = gra;
  gra=gra->nastepny();
  delete poprzedni; //musimy zwalaniać pamięc przydzielaną przez new!
  gra->play(ala); //zależy od tego co wybraliśmy!
  delete gra;
  return 0;
}
0

Dzięki za naprawdę cenne rady :) W sumie sam nie wiem czemu wcześniej nie wpadłem, że pobieranie adresu jest bez sensu. Jeszcze raz dzięki!

1 użytkowników online, w tym zalogowanych: 0, gości: 1