Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 516

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

1

14.09.2015, 18:43

[C++] Ärger mit unique_ptr

Hallo Leute,

zurzeit programmiere ich einem Spiel. Das Spiel hat natürlich ein Hauptmenü, mit Buttons, um die GameSttates zu wechseln. Für jeden State (MainMenue, OptionState, ...) benutze ich einen unique_ptr. Hier die Codeausschnitte:

Statemanager.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#pragma once

#include <memory>
#include <map>
#include <iostream>

#include "GameState.hpp"
#include "gamestates\states\include\MainMenuState.hpp"
#include "gamestates\states\include\OptionState.hpp"

class MainMenuState;
class OptionState;
class Game;
class GameState;

class StateManager
{
public:
    // PLAY = Levelauswahl
    enum GameStates
    {
        MAINMENUE,
        PLAY,
        HELP,
        OPTIONS
    };
        void ChangeState(GameStates newState);

        // ...


private:
       // ...

    std::map<std::string, GameState*> m_States;

    GameState* m_CurrentState;

    // Die verschiedenen States aufrufen als Instanz oder als Pointer
    std::unique_ptr<MainMenuState> m_MainMenuState;
    std::unique_ptr<OptionState> m_OptionState;

};


Statemanager.cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
StateManager::StateManager(Game &game)
    :m_CurrentState(nullptr) // Den CurrentState auf Null setzen
{
    m_MainMenuState = std::make_unique<MainMenuState>();
    m_OptionState = std::make_unique<OptionState>();

        // ...
}

// ...

void StateManager::ChangeState(GameStates newState)
{
    switch (newState)
    {
    case MAINMENUE:
        break;

    case PLAY:
        break;
    case HELP:
        break;
    case OPTIONS:
        m_CurrentState = std::move(std::unique_ptr<OptionState>(new OptionState));
        break;

    default:
        throw std::runtime_error("unique_ptr konnte nicht verschoben werden.");

    }

}


OptionState.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#pragma once

#include <memory>
#include <iostream>

#include "core\include\Game.hpp"
#include "gamestates\include\GameState.hpp"
#include "gui\include\Button.h"
#include "gui\include\Gui.h"
#include "gui\include\Checkbox.h"
#include "gui\include\Slider.h"

class Game;
class GameState;

class OptionState : public GameState
{
public:
    OptionState();
    ~OptionState();

    void Update(Game &game) override;
    void ProcessEvents(Game &game) override;
    void Render(sf::RenderWindow &App) override;

    /*void EnterState(sf::RenderWindow &App) override;
    void LeaveState(sf::RenderWindow &App) override;*/

    void LoadOptionAssets();
    void AddWidgetes();

private:
    SGui::Gui Gui;

    SGui::Button BackToMenueButton;

    SGui::Checkbox MusicEnabled;

    SGui::Slider MusicVolume;

};


Nun bekomme ich folgende Fehlermeldung:
Fehler 1 error C2259: 'OptionState': Instanz von abstrakter Klasse kann nicht erstellt werden
Fehler 2 error C2440: '=': 'std::unique_ptr<OptionState,std::default_delete<_Ty>>' kann nicht in 'GameState *' konvertiert werden

Welche Fehler habe ich gemacht?
Vielen Dank im Voraus :)

2

14.09.2015, 19:10

C-/C++-Quelltext

1
2
GameState* m_CurrentState;
m_CurrentState = std::move(std::unique_ptr<OptionState>(new OptionState));


std::unique_ptr<OptionState> != Gamestate

Mal davon abgesehen das diese zuweisung auf m_curentState quatsch ist, den Pointer auf das Objekt gibt es über get()-Methode von std::unique_ptr.

Kann sein da es Beide probleme löst wenn den Fehler behebst.

Edit: Eventuell sind die Methoden Abstract in der Classe GameState

C-/C++-Quelltext

1
2
 /*void EnterState(sf::RenderWindow &App) override;
    void LeaveState(sf::RenderWindow &App) override;*/

wenn die in OptionState nicht enthalten sind wird die Klasse auch Abstract.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 516

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

3

14.09.2015, 19:39

Danke für die Antwort, ich sehe es mit mal heute Nacht oder morgen früh an :)

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 516

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

4

15.09.2015, 06:55

Also ich habe es jetzt so gemacht:

Statemanager.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#pragma once

#include <memory>
#include <map>
#include <iostream>

#include "GameState.hpp"
#include "gamestates\states\include\MainMenuState.hpp"
#include "gamestates\states\include\OptionState.hpp"

class MainMenuState;
class OptionState;
class Game;
class GameState;

class StateManager
{
public:
    // PLAY = Levelauswahl
    enum GameStates
    {
        MAINMENUE,
        PLAY,
        HELP,
        OPTIONS
    };

    StateManager(Game &game);
    ~StateManager();

    void Update(Game &game);
    void ProcessEvents(Game &game);
    void Render(sf::RenderWindow &App);

    // getter
    // Es muss ein Pointer sein weil es eine virtuelle Klasse ist
    GameState* GetState(std::string id);

    void ChangeState(GameStates newState);

private:
    void AddState(GameState& state);
    void SetState(std::string id, Game &game);

    void LoadAssets();

    std::map<std::string, GameState*> m_States;

    std::unique_ptr<GameState> m_CurrentState;

    // Die verschiedenen States aufrufen als Instanz oder als Pointer
    std::unique_ptr<MainMenuState> m_MainMenuState;
    std::unique_ptr<OptionState> m_OptionState;

};


Statemanager.cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
StateManager::StateManager(Game &game)
    :m_CurrentState(nullptr) // Den CurrentState auf Null setzen
{
    m_CurrentState = std::make_unique<GameState>("CurrentState");
    m_MainMenuState = std::make_unique<MainMenuState>();
    m_OptionState = std::make_unique<OptionState>();
// ...
}

// ...

void StateManager::ChangeState(GameStates newState)
{
    switch (newState)
    {
    case MAINMENUE:
        break;

    case PLAY:
        break;
    case HELP:
        break;
    case OPTIONS:
        m_CurrentState = std::move(std::unique_ptr<OptionState>(new OptionState));
        break;

    default:
        throw std::runtime_error("unique_ptr konnte nicht verschoben werden.");

    }

}


Jetzt habe ich folgende Fehlermeldung noch:
Fehler 1 error C2259: 'GameState': Instanz von abstrakter Klasse kann nicht erstellt werden

5

15.09.2015, 07:09

Dann ist in GameState oder einer Klasse, von der GameState erbt, eine rein-virtuelle Funktion (z.B. virtual void HelloWorld() = 0) vorhanden. Die muss natürlich implementiert werden.
Cube Universe
Entdecke fremde Welten auf deiner epischen Reise durchs Universum.

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 516

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

6

15.09.2015, 07:50

Dann ist in GameState oder einer Klasse, von der GameState erbt, eine rein-virtuelle Funktion (z.B. virtual void HelloWorld() = 0) vorhanden. Die muss natürlich implementiert werden.

Alle Klassen, die von GameState erben: OptionState, MainMenuState
(Alle virtuellen Funktionen sind mit einem override versehen und definiert)

OptionState.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#pragma once

#include <memory>
#include <iostream>

#include "core\include\Game.hpp"
#include "gamestates\include\GameState.hpp"
#include "gui\include\Button.h"
#include "gui\include\Gui.h"
#include "gui\include\Checkbox.h"
#include "gui\include\Slider.h"

class Game;
class GameState;

class OptionState : public GameState
{
public:
    OptionState();
    ~OptionState();

    void Update(Game &game) override;
    void ProcessEvents(Game &game) override;
    void Render(sf::RenderWindow &App) override;

    void EnterState(sf::RenderWindow &App) override;
    void LeaveState(sf::RenderWindow &App) override;

    void LoadOptionAssets();
    void AddWidgetes();

private:
    SGui::Gui Gui;

    SGui::Button BackToMenueButton;

    SGui::Checkbox MusicEnabled;

    SGui::Slider MusicVolume;

};


MainMenuState.hpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma once

#include <memory>

#include "core\include\Game.hpp"
#include "gamestates\include\GameState.hpp"
#include "gui\include\Button.h"
#include "gui\include\Gui.h"

class GameState;
class Game;

class MainMenuState : public GameState
{
public:
    MainMenuState();
    ~MainMenuState();

    void Update(Game &game) override;
    void ProcessEvents(Game &game) override;
    void Render(sf::RenderWindow &App) override;

    void EnterState(sf::RenderWindow &App) override;
    void LeaveState(sf::RenderWindow &App) override;

    void loadMenuAssets();
    void AddWidgetes();

private:
    sf::Font font;
    sf::Text Headline;

    SGui::Button StartButton;
    SGui::Button OptionButton;
    SGui::Button HelpButton;
    SGui::Button ExitButton;

    SGui::Gui Gui;

};


Wieso finde ich den Fehler nicht :dash:

EDIT: Hier GameState.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#pragma once

#include <string>

#include "core\include\Game.hpp"

class Game;

class GameState
{
public:
    GameState(std::string id) : m_bJoined(false), m_NextState(""), m_ID(id) {};

    virtual void Update(Game &game) = 0;
    virtual void ProcessEvents(Game &game) = 0;
    virtual void Render(sf::RenderWindow &App) = 0;

    virtual void EnterState(sf::RenderWindow &App) = 0;
    virtual void LeaveState(sf::RenderWindow &App) = 0;

    void setID(std::string id) { m_ID = id; };
    void setNextState(std::string nextState) { m_NextState = nextState; };
    void setJoined(bool joined) { m_bJoined = joined; };

    std::string getID()         { return m_ID; };
    std::string getNextState()  { return m_NextState; };
    bool getJoined()            { return m_bJoined; };

private:
    std::string m_ID;
    std::string m_NextState;

    bool m_bJoined;
};

Tobiking

1x Rätselkönig

  • Private Nachricht senden

7

15.09.2015, 07:58


Alle Klassen, die von GameState erben: OptionState, MainMenuState
(Alle virtuellen Funktionen sind mit einem override versehen und definiert)

GameState selber ist aber abstrakt. Und mit dem std::make_unique versuchst du eine Instanz von GameState zu erzeugen.

8

15.09.2015, 09:52

Und

C-/C++-Quelltext

1
        m_CurrentState = std::move(std::unique_ptr<OptionState>(new OptionState));

Wird nicht das gewünschte Ergebnis liefern. Du erzeugst hier immer eine neue Instanz anstatt die bestehende Instanz dem RAW-Pointer zuzuweisen.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

9

15.09.2015, 09:56

Warum ueberhaupt unique pointer, wenn sie dann doch nicht unique sein sollen?

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

10

15.09.2015, 11:03

unique heißt ja nur ein Besitzer. Andere dürfen dürfen das Objekt über Raw-Pointer/Referenzen ja durchaus assoziieren. So fährt man meiner Erfahrung nach ziemlich gut, und Delete-Aufrufe sind gar nicht mehr nötig.

Werbeanzeige