invalid use of incomplete type / forward declaration



  • 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?



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

    = default 
    

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

    Was heißt "macht trivial"?
    Warum er das macht: Ein destructor wird hier eigentlich nicht benötigt, muss aber doch angegeben werden, da der destructor virtual sein muss.
    Daher das für jeden sofort ersichtliche "virtual ~dtor() = default" statt einer leeren Definition irgendwo im cpp.

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

    Was genau macht diese Zeile?

    Macht context zum Owner von dem handle_input-Rückgabewert. Kann auch nullptr sein, daher hat er den Besitz nicht gemoved.
    Sehr kompakt, allerdings fand ich das trotzdem auch schwer zu lesen.

    Wobei...eigentlich auch wurscht, nee, verstehe ich doch nicht, warum nicht einfach "context = context->handle_input();"


Anmelden zum Antworten