Tablica klasy-wskaźnik zrobiona ze wskaźnika

0

Cześć! Robię klasę ScreenManager, która przechowuje tablicę klas GameScreen (klasa matki dla wszystkich klas typu: menu, pause, options, etc.). Mogę zrobić to wektorem i po kłopocie, ale chciałem sobie sprawdzić jak zrobić to podwójną gwiazdką. Niestety tak niekoniecznie chce to działać:

	class MainGame;
	class GameScreen;

	class ScreenManager
	{
	public:
		ScreenManager(MainGame* game);

		GameScreen* MoveNext();
		GameScreen* MovePrevious();

		void StartScreen(size_t ScreenIndex);
		void AddScreen(GameScreen* newScreen);

		GameScreen* getCurrent();

	private:
		friend class MainGame;

		MainGame* game = nullptr;

		GameScreen** screens = nullptr;
		int screenSize = 0;
		size_t currentScreenIndex = -1;
	};
	ScreenManager::ScreenManager(MainGame *Game) : game(Game) {}

	GameScreen* ScreenManager::MoveNext()
	{
		GameScreen* currentScreen = getCurrent();
		if (currentScreen->getNextScreenIndex() != SCREEN_INDEX_NO_SCREEN) {
			currentScreenIndex = currentScreen->getNextScreenIndex();
		} else std::cout << "No next screen index!" << std::endl;
		return getCurrent();
	}

	GameScreen* ScreenManager::MovePrevious()
	{
		GameScreen* currentScreen = getCurrent();
		if (currentScreen->getPreviousScreenIndex() != SCREEN_INDEX_NO_SCREEN) {
			currentScreenIndex = currentScreen->getPreviousScreenIndex();
		} else std::cout << "No previous screen index!" << std::endl;

		return getCurrent();
	}

	void ScreenManager::StartScreen(size_t ScreenIndex)
	{
		currentScreenIndex = ScreenIndex;
	}

	void ScreenManager::AddScreen(GameScreen* newScreen)
	{
		newScreen->setScreenIndex(screenSize);
		screens[screenSize] = newScreen;
		++screenSize;
		newScreen->game = game;
	}

	GameScreen* ScreenManager::getCurrent()
	{
		if (currentScreenIndex == SCREEN_INDEX_NO_SCREEN) return nullptr;
		return screens[currentScreenIndex];
	}

Po dodaniu i ustawieniu ekranu startowego pojawia się błąd :

Exception thrown: write access violation.
this->screens was 0x1110112.

A callstack kieruje mnie do 37 linii, tzn screens[screenSize] = newScreen;

W jaki sposób napisać to żeby działało?

0

Nigdzie nie inicjujesz wskaźnika screens - cały czas wskazuje na nullptr.

0

Jak to? Ustawiam dla screens na pozycji screenSize agrument GameScreen* newScreen w metodzie AddScreen i za każdym wywołaniem metody AddScreen zwiększam ilość okien (screenSize) o 1 żeby "nie nachodziły" na siebie klasy.

0

Ok, ustawiasz screens[screenSize], natomiast nigdzie nie robisz żadnego screens = new GameScreen*[rozmiarTablicyScreens];, zatem masz tam null pointer dereference ;-)

2

Mogę zrobić to wektorem i po kłopocie,

No to tak zrób.

chciałem sobie sprawdzić jak zrobić to podwójną gwiazdką.

Będzie źle.

0

Ok, ustawiasz screens[screenSize], natomiast nigdzie nie robisz żadnego screens = new GameScreen*[rozmiarTablicyScreens];, zatem masz tam null pointer dereference ;-)

Tak, zdecydowanie masz racje. Bardzo często używam wektorów i pominąłem ten etap :/ Dzięki wielkie!

Mogę zrobić to wektorem i po kłopocie,

No to tak zrób.

No mogę zrobić i raczej przy tym zostanę, ale chciałem sobie poeksperymentować

Będzie źle.

Dlaczego?

1

Będzie źle, ponieważ będzie nieidiomatycznie. Ale źle też zrozumiałem Twój post. Edukacyjnie to spoko.

0

A ten cały ScreenManager to do czego jest Ci potrzebny? Nie lepiej żeby każdy ekran posiadał po prostu wskaźnik do poprzedniego/następnego ekranu?

0

Ekranów może być klika. Na przykład z main menu można przejść do new game, load game, options, itd. Wydaje mi się, że lepiej wszystko będzie wyglądać jak zrobię sobie klasę ScreenManager, która będzie posiadać wszystkie ekrany, dodawać i usuwać je w jedynm miejscu zamiast chodzić po różnych klasach.

0

Myślałem, że m.in po to masz klasę GameScreen po której można dziedziczyć. W przypadku gdy jest klika opcji do wyboru tworzysz klasę pochodną, która rozszerza funkcjonalność z klasy bazowej i pozwala wybrać, który ekran ma być tym następnym.

Ale oczywiście podejść do tematu może być kilka. Ja zwyczajnie mam awersję do wszelkiej maści 'menedżerów' ;)

0

Ale w twoim wypadku musiałbym w każdej klasie robić pointer/objekt klasy następnej i poprzedniej. Wydaje mi się, że lepiej raz w Klasie głównej zrobić sobie metodę, która dodaje klasy np.

void MainGame::SetupMainScreen()
{
	screenManager.AddScreen(new MenuGlowne); 
	screenManager.AddScreen(new Nowa);
	screenManager.AddScreen(new Wczytaj);
	screenManager.AddScreen(new Opcje);
}

void MainGame::SetupOptionScreen()
{
	screenManager.AddScreen(new Sterowanie);
	screenManager.AddScreen(new Dzwiek);
	screenManager.AddScreen(new Ekran);
}

I w konstruktorze wywołać te dwie metody i wtedy enumem
{
MenuGlowne = 0,
Nowa = 1,
...
}

W kolejności dodawania do sceenManagera

I wtedy jak jestem na przykład w MenuGlowne i chce przejsc do Nowa gra to w metodzie int nextScreenIndex() zwracam Nowa = 1 i przechodzę ładnie do nowej gry.

Oszczędzam wtedy miejsce w klasach pochodnych do GameSceen i nie musze usuwać cały czas wskaźników do klas, bo robi to za mnie screen manager i pamięć alokuje się na samym początku gry, a nie w momencie zmieniania klas z jednej na drugą.

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