invalid use of incomplete type / forward declaration



  • @daniel

    Wenn ich #include "StateMachine.h" in den State Header schreibe, erscheinen noch viel mehr Fehler

    Dann behebe die Fehler.

    MainMenuState *currentState; Warum ist das nicht State*?



  • Dieser Beitrag wurde gelöscht!


  • @manni66 Hab es geändert; so sehen die Fehlermeldungen aus:

    StateMachine.h:6:2: error: ‘State’ does not name a type; did you mean ‘static’?
      State *currentState;
      ^~~~~
      static
    In file included from main.cpp:1:0:
    StateMachine.h:4:7: error: redefinition of ‘class StateMachine’
     class StateMachine
           ^~~~~~~~~~~~
    In file included from State.h:2:0,
                     from MainMenuState.h:2,
                     from StateMachine.h:1,
                     from main.cpp:1:
    StateMachine.h:4:7: note: previous definition of ‘class StateMachine’
     class StateMachine
           ^~~~~~~~~~~~
    In file included from State.h:2:0,
                     from MainMenuState.h:2,
                     from StateMachine.h:1,
                     from StateMachine.cpp:1:
    StateMachine.h:6:2: error: ‘State’ does not name a type; did you mean ‘static’?
      State *currentState;
      ^~~~~
      static
    In file included from StateMachine.cpp:1:0:
    StateMachine.h:4:7: error: redefinition of ‘class StateMachine’
     class StateMachine
           ^~~~~~~~~~~~
    In file included from State.h:2:0,
                     from MainMenuState.h:2,
                     from StateMachine.h:1,
                     from StateMachine.cpp:1:
    StateMachine.h:4:7: note: previous definition of ‘class StateMachine’
     class StateMachine
           ^~~~~~~~~~~~
    StateMachine.cpp: In constructor ‘StateMachine::StateMachine()’:
    StateMachine.cpp:5:2: error: ‘currentState’ was not declared in this scope
      currentState = new MainMenuState();
      ^~~~~~~~~~~~
    StateMachine.cpp:5:2: note: suggested alternative: ‘MainMenuState’
      currentState = new MainMenuState();
      ^~~~~~~~~~~~
      MainMenuState
    StateMachine.cpp: In member function ‘void StateMachine::run()’:
    StateMachine.cpp:10:2: error: ‘currentState’ was not declared in this scope
      currentState->handleEvents(*this);
      ^~~~~~~~~~~~
    StateMachine.cpp:10:2: note: suggested alternative: ‘MainMenuState’
      currentState->handleEvents(*this);
      ^~~~~~~~~~~~
      MainMenuState
    In file included from State.h:2:0,
                     from MainMenuState.h:2,
                     from MainMenuState.cpp:1:
    StateMachine.h:6:2: error: ‘State’ does not name a type; did you mean ‘static’?
      State *currentState;
      ^~~~~
      static
    


    1. in StaeMachine.h fehlt das pragma once

    2. In file included from State.h:2:0,
      from MainMenuState.h:2,
      from StateMachine.h:1,
      from main.cpp:1:

    Wozu braucht StateMachin.h MainMenuState.h? Für State* reicht eine simple Vorwärtsdeklaration.



  • @daniel sagte in invalid use of incomplete type / forward declaration:

    currentState = new MainMenuState();	
    

    Warum new?

    @daniel sagte in invalid use of incomplete type / forward declaration:

    Mit new erstelle ich das Objekt doch auf dem Heap, muss also das löschen explizit aufrufen.

    Selbst wenn. Das macht man schon seit Jahren nicht mehr so. RAII, Smartpointer.

    @daniel sagte in invalid use of incomplete type / forward declaration:

    Und ich möchte das löschen nicht durch das Ende eines bereiches hervorrufen. Ist das so richtig?

    Ja, Jein, Nein. Welcher Bereich? Meinst Du Scope (also Block, etwas zwischen { und }? Wenn ja, welchen Scope hat denn Dein currentState?



  • @manni66 Weil die StateMachine alle möglichen States braucht. Also MainMenuState und später auch GameState usw



  • @Swordfish Ja ich habe smartpointer gesehen aber ich möchte erstmal mit den Pointern völlig klarkommen, bevor ich damit anfange.



  • @daniel sagte in invalid use of incomplete type / forward declaration:

    @manni66 Weil die StateMachine alle möglichen States braucht. Also MainMenuState und später auch GameState usw

    Auf welche Frage von @manni66 ist das die Antwort?



  • @daniel sagte in invalid use of incomplete type / forward declaration:

    @manni66 Weil die StateMachine alle möglichen States braucht. Also MainMenuState und später auch GameState usw

    Im Header?



  • @daniel sagte in invalid use of incomplete type / forward declaration:

    ich möchte erstmal mit den Pointern völlig klarkommen

    Kommst du nicht. Deswegen gibt es Smartpointer.



  • Dieser Beitrag wurde gelöscht!


  • @Swordfish auf die Zweite
    @manni66 stimmt, nur in der implementierung
    @manni66 Okay aber ein Smartpointer ist doch nur ein Pointer mit automatisierter Garbage collection oder? Wie sähe eine implementierung davon in diesem Beispiel aus?



  • @daniel sagte in invalid use of incomplete type / forward declaration:

    nur ein Pointer mit automatisierter Garbage collection oder?

    Nein. Aber selbst wenn es so wäre: was möchtest du damit sagen?



  • @manni66 War eher eine Frage.
    Also das ist jetzt die StateMachine.h mit smartpointer:

    #pragma once
    #include "MainMenuState.h"
    #include <memory>
    #include "State.h"
    
    class StateMachine
    {
    private:
    	std::unique_ptr<State> currentState;
    public:
    	StateMachine();
    	void run();
    
    

    StateMachine.cpp:

    #include "StateMachine.h"
    
    StateMachine::StateMachine()
    {
    	currentState = std::move(std::unique_ptr<MainMenuState>(new MainMenuState));
    }
    
    void StateMachine::run()
    {
    	currentState->handleEvents(*this);
    }
    

    Und State.h, welche StateMachine includiert

    #pragma once
    #include "StateMachine.h"
    
    class State
    {
    public:
    	virtual void handleEvents(StateMachine &sm) = 0;
    };
    

    Das ergibt allerdings wieder folgende Fehler:

    In file included from MainMenuState.h:2:0,
                     from StateMachine.h:2,
                     from main.cpp:1:
    State.h:7:28: error: ‘StateMachine’ has not been declared
      virtual void handleEvents(StateMachine &sm) = 0;
                                ^~~~~~~~~~~~
    In file included from StateMachine.h:2:0,
                     from main.cpp:1:
    MainMenuState.h:8:20: error: ‘StateMachine’ has not been declared
      void handleEvents(StateMachine &sm);
                        ^~~~~~~~~~~~
    In file included from MainMenuState.h:2:0,
                     from StateMachine.h:2,
                     from StateMachine.cpp:1:
    State.h:7:28: error: ‘StateMachine’ has not been declared
      virtual void handleEvents(StateMachine &sm) = 0;
                                ^~~~~~~~~~~~
    In file included from StateMachine.h:2:0,
                     from StateMachine.cpp:1:
    MainMenuState.h:8:20: error: ‘StateMachine’ has not been declared
      void handleEvents(StateMachine &sm);
                        ^~~~~~~~~~~~
    StateMachine.cpp: In member function ‘void StateMachine::run()’:
    StateMachine.cpp:10:34: error: no matching function for call to ‘State::handleEvents(StateMachine&)’
      currentState->handleEvents(*this);
                                      ^
    In file included from MainMenuState.h:2:0,
                     from StateMachine.h:2,
                     from StateMachine.cpp:1:
    State.h:7:15: note: candidate: virtual void State::handleEvents(int&)
      virtual void handleEvents(StateMachine &sm) = 0;
                   ^~~~~~~~~~~~
    State.h:7:15: note:   no known conversion for argument 1 from ‘StateMachine’ to ‘int&’
    In file included from State.h:2:0,
                     from MainMenuState.h:2,
                     from MainMenuState.cpp:1:
    StateMachine.h:9:18: error: ‘State’ was not declared in this scope
      std::unique_ptr<State> currentState;
                      ^~~~~
    StateMachine.h:9:18: note: suggested alternative: ‘getdate’
      std::unique_ptr<State> currentState;
                      ^~~~~
                      getdate
    StateMachine.h:9:23: error: template argument 1 is invalid
      std::unique_ptr<State> currentState;
                           ^
    StateMachine.h:9:23: error: template argument 2 is invalid
    
    

    Habe ich vieleicht eine Falsche herangehensweise? Könnt ihr mir vieleicht ein extrem vereinfachtes Beispiel für eine StateMachine zeigen?



  • Auch für Referenzen reicht eine Vorwärtsdeklaration. Entferne das include StateMachine aus dem State Header.



  • #include "MainMenuState.h" warum steht das immer noch im Header?



  • Okay hab das gemacht und es funktioniert alles. Vielen Dank!



  • @daniel sagte in invalid use of incomplete type / forward declaration:

    Wie sähe eine implementierung davon in diesem Beispiel aus?

    context.h

    #pragma once
    
    #include <memory>
    
    struct context_t
    {
    	virtual void present() const = 0;
    	virtual std::unique_ptr<context_t> handle_input() = 0;
    	virtual ~context_t() = default;
    };
    

    title_screen_context.h

    #pragma once
    
    #include "context.h"
    
    struct title_screen_context_t final : context_t
    {
    	virtual void present() const override;
    	virtual std::unique_ptr<context_t> handle_input() override;
    };
    

    title_screen_context.cpp

    #include "title_screen_context.h"
    #include "main_menu_context.h"
    
    #include <iostream>
    
    void title_screen_context_t::present() const
    {
    	std::cout << "title screen\n\npress enter\n\n";
    }
    
    std::unique_ptr<context_t> title_screen_context_t::handle_input()
    {
    	std::cin.get();
    	return std::make_unique<main_menu_context_t>();
    }
    

    main_menu_context.h

    #pragma once
    
    #include "context.h"
    
    struct main_menu_context_t final : context_t
    {
    	virtual void present() const override;
    	virtual std::unique_ptr<context_t> handle_input() override;
    };
    

    main_menu_context.cpp

    #include "main_menu_context.h"
    #include "credits_context.h"
    
    #include <iostream>
    
    void main_menu_context_t::present() const
    {
    	std::cout << "[1] menu item 1\n[2] menu item 2\n[3] menu item 3\n[0] exit\n";
    }
    
    std::unique_ptr<context_t> main_menu_context_t::handle_input()
    {
    	int choice;
    	std::cin >> choice;
    
    	switch (choice) {
    	case 0:
    		return std::make_unique<credits_context_t>();
    	case 1:
    		return std::make_unique<main_menu_context_t>();  // todo: context fuer menuepunkt 1
    	case 2:
    		return std::make_unique<main_menu_context_t>();  // todo: context fuer menuepunkt 2
    	case 3:
    		return std::make_unique<main_menu_context_t>();  // todo: context fuer menuepunkt 3
    	}
    
    	return std::make_unique<main_menu_context_t>();
    }
    

    credits_context.h

    #pragma once
    
    #include "context.h"
    
    struct credits_context_t final : context_t
    {
    	virtual void present() const override;
    	virtual std::unique_ptr<context_t> handle_input() override;
    };
    

    credits_context.cpp

    #include "credits_context.h"
    #include "main_menu_context.h"
    
    #include <iostream>
    
    void credits_context_t::present() const
    {
    	std::cout << "Credits: ...\n\nReally Exit? [y|n]\n";
    }
    
    std::unique_ptr<context_t> credits_context_t::handle_input()
    {
    	char choice;
    	std::cin >> choice;
    
    	if (choice == 'y')
    		return nullptr;
    
    	return std::make_unique<main_menu_context_t>();
    }
    

    machine.h

    #pragma once
    
    #include <memory>
    
    #include "title_screen_context.h"
    
    struct machine_t final
    {
    	std::unique_ptr<context_t> context = std::make_unique<title_screen_context_t>();
    	void run();
    };
    

    machine.cpp

    #include "machine.h"
    
    void machine_t::run()
    {
    	while (context) {
    		context->present();
    		context.reset(context->handle_input().release());
    	}
    }
    

    main.cpp

    #include "machine.h"
    
    int main()
    {
    	machine_t{}.run();
    }
    


  • @Swordfish Oh wow danke, damit muss ich mich jetzt erstmal beschäftigen



  • @Swordfish

    = default 
    

    Das macht die struct trivial glaube ich, warum benutzt du das?

    context.reset(context->handle_input().release());
    

    Was genau macht diese Zeile?


Anmelden zum Antworten