Podstawy - Przekazywanie obiektu do settera.

0

Witajcie.

Mam drobny problem z przekazaniem obiektu jako referencja do settera. Chcę ten obiekt przypisać do zmiennej/referencji/wskaźnika typu GameState, ale szukam informacji i nie mogę znaleźć żadnych danych. Jeżeli ktoś ma jakiś pomysł, byłbym wdzięczny za wytłumaczenie :)

Poniżej wstawiam kod programu:


Tutaj mamy nagłówki:

#ifndef GAMESTATE_H
#define GAMESTATE_H

#include "../../classes/states/States.cpp"

class GameState {
public:
    GameState();
    virtual void init() =0;
    virtual void update() =0;
    virtual void render() =0;
    virtual void input();
    virtual void setState(GameState&);
    virtual GameState& getState() const;
    virtual ~GameState();
private:
    GameState *gameState;

};

#endif // GAMESTATE_H

#ifndef GAMESTATEMANAGER_H
#define GAMESTATEMANAGER_H

#include "GameState.h"
#include "PlayState.h"
//#include "../../classes/states/States.cpp"

class GameStateManager {
public:
    GameStateManager();
    GameState *gameState;		// <- Zmienna ma być zapisana do tego parametru
    int state;
    ~GameStateManager();

    void setState(int);
    void currentState();
    int getState();
};

#endif // GAMESTATEMANAGER_H
#ifndef PLAYSTATE_H
#define PLAYSTATE_H

class PlayState : GameState {

public:
    PlayState();
    void init();
    void update();
    void render();
    void input();
    ~PlayState();

};

#endif // PLAYSTATE_H

Tutaj mamy pliki źródłowe:

#include "../../headers/states/GameState.h"

void GameState::setState(GameState & s) {
    *gameState = s;
}

GameState& GameState::getState() const {
    return *gameState;
}
#include "../../headers/states/GameStateManager.h"

GameStateManager::GameStateManager() {

}

void GameStateManager::setState(int s) {
    state = s;
    currentState();
}

void GameStateManager::currentState() {
    if(state == 1) {
        // @todo implement MenuState class
        //gameState = new MenuState(this);
    }
    if(state == 2) {
            // @todo make PlayState class not abstract
        PlayState playState;				
        GameState::setState(playState);			// <- TUTAJ WYSKAKUJE BLAD
    }
}


/** GameStateManager::getState() - returns current state
*   @return int state - returns int type responsible for state
*/
int GameStateManager::getState() {
    return state;
}
#include "../../headers/states/PlayState.h"

PlayState::PlayState() {

}

void PlayState::init() {

}

void PlayState::update() {

}

void PlayState::render() {

}

void PlayState::input() {

}

voit PlayState::init() {

}

PlayState::~PlayState() {

}
0

Probowales z gwiazdka przed tym s ? Moj mozg dzisiaj kiepsko pracuje (wybaczam mu to w takiej temperaturze) wiec moge sie mylic.

0

*gameState dereferencja niezainicjalizowanego wskaźnika powoduje seg fault. Powinno być
gameState = &s;
Wskaźnikowi przypisujesz adres s.

0

Kiedy definicja wygląda tak:

void GameState::setState(GameState & s) {
    gameState = *s;
}

to kompilator krzyczy:

error: no match for 'operator*' (operand type is 'GameState')

(Błąd dotyczy oczywiście wiersza

gameState = *s;
0

Ampresand, nie *. Wyzej masz napisane nawet.

0

Faktycznie, my bad :). Tak zrobiłem, jednak kompilatorowi dalej sie nie podoba:

||=== Build: Debug in Breakout (compiler: GNU GCC Compiler) ===|
C:\C++\Workspace\Breakout\classes\states\GameStateManager.cpp||In member function 'void GameStateManager::currentState()':|
C:\C++\Workspace\Breakout\classes\states\GameStateManager.cpp|20|error: cannot call member function 'virtual void GameState::setState(GameState&)' without object|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 3 second(s)) ===|
0

Jesli chcesz funkcje wywolywac bez tworzenia jej obiektu (GameState::setState) to ta funkcja musi byc statyczna. W ogole strasznie dziwnie to wymysliles.

0

Czytaj co kompilator Ci podpowiada.
cannot call member function 'virtual void GameState::setState(GameState&)' without object
Nie może wywołać funkcji GameState::setState bez obiektu. Musisz stworzyć obiekt GameState, żeby wywołać funkcję setState. Robisz to w następujący sposób:

GameState obiekt;
obiekt.setState(arg);

Ewentualnie:

GameState *obiekt = new GameState;
obiekt->setState(arg);
0

A no właśnie, a jeśli chciałbym zwyczajnie przechować taką zmienną jako typ GameState ? (GameState jest klasą abstrakcyjną). Czy takie coś jest w ogóle możliwe ?

0

Wat ? Jezeli jest klasa abstrakcyjna to po co Ci setery i co bys chcial przechowywac w klasie abstrakcyjnej ? 0o Stworz po prostu obiekt i uzywaj jak zwyklej klasy.

0
Lukasz_ napisał(a):

Wat ? Jezeli jest klasa abstrakcyjna to po co Ci setery i co bys chcial przechowywac w klasie abstrakcyjnej ? 0o Stworz po prostu obiekt i uzywaj jak zwyklej klasy.

Dlaczego tak się przyczepiłem ? Swego czasu pisałem w Javie, a tam klasa abstrakcyjna (tak jak w c++, nie mogła tworzyć obiektu, ale...) mogła przechowywać zmienne obiektowe klasy która po niej dziedziczy, jak np. ten obiekt PlayState. Poza tym, chcę aby klasy dziedziczące po GameState miały z góry narzucone funkcje które są niezbędne do ich działania po wywołaniu obiektu, a oprócz tego przypadku nie ma potrzeby wywołania obiektu klasy GameState. Chyba że jest jakiś inny sposób.

A czy dało by się po prostu zaalokować obiekt PlayState do pamięci i zapisać go we wskaźniku gameState ?

w GameState.h

GameState *gameState;

w GameStateManager.cpp

*gameState = new PlayState();
0

Mowilem, mozesz zrobic to static, ale wtedy bedziesz mial tylko jedno takie pole na klase. Kazdy obiekt bedzie dzialal na tym samym. Bez tej gwiazdki w drugim.

0

@Lukasz_ Może dlatego, że mam już mózg wyprany po pracy xD. Ok to po kolei:

Chcę aby klasa GameState była wzorem stanów gry (np. Menu, Gra, Cutscenki, Creditsy itp.). Każda z klas która będzie po niej dziedziczyć, będzie mieć szereg metod które muszą przeciążać (np. renderowanie, sterowanie itp.). Klasa GameStateManager, jak nazwa mówi, będzie zarządzać, który stan (obiekt) będzie akurat wywoływany. Najlepiej by było, gdyby obiekt (czy to PlayState czy MenuState czy CutsceneState itp.) mógł być przechowywany w zmiennej tego samego typu dla każdej z klas, np.

GameState gameState = new PlayState(); // przy wywołaniu stanu gry
GameState gameState = new MenuState(); // przy wywołaniu stanu menu głównego

itd. bo wtedy będzie mi łatwiej zmieniać stany. Jeżeli jest jakieś inne wyjście, to będę zadowolony poznając je, choć nie ukrywam że ambicja karze mi rozwiązać i ten problem :P

1
#include <memory>
#include <iostream>
#include <string>
#include <map>
#include <array>
using namespace std;

/* abstract base */
struct GameState{
	virtual string info() const = 0;
};
string GameState::info() const{
	return "GameState.info: ";
}
typedef shared_ptr<GameState> state_ptr;

/* child 1 */
struct MenuState : GameState{
	string info() const{ return GameState::info() + "Menu"; }
};

/* child 2 */
struct PlayState : GameState{
	string info() const{ return GameState::info() + "Play"; }
};

/* GameState creator func */
template<class T>
state_ptr create(){ return shared_ptr<GameState>(new T()); }
typedef state_ptr (*create_fptr)();

class Manager{
private:
	state_ptr m_state;
public:
	state_ptr state(){ return m_state; }
	state_ptr state(string name){
		static map<string, create_fptr> create_funcs = {
			{{"Menu"}, {create<MenuState>}},
			{{"Play"}, {create<PlayState>}}
		};
		return m_state = create_funcs[name]();
	}
	state_ptr state(state_ptr state){
		return m_state = state;
	}
};

/* tests */
int main(){
	Manager m;
	
	array<string, 2> names = 
		{ "Menu", "Play" };
	array<state_ptr, 2> objects = 
		{ create<PlayState>(), create<MenuState>() };
		
	for(auto name : names)
		cout << m.state(name)->info() << endl;
	for(auto object : objects)
		cout << m.state(object)->info() << endl;
		
	return 0;
}

stdout:

GameState.info: Menu
GameState.info: Play
GameState.info: Play
GameState.info: Menu

http://ideone.com/nEMYNG

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