Klasse für Menüitems - Error C4430
-
Also bei sf::Font wird kein Error ausgegeben und das Funktioniert auch auf jeden Fall; hatte vorher schon die Menüitems einzeln und nicht als eigene Klasse programmiert, da hat es auch geklappt.
sf::Font müsste er durch den include von Game.h bereits kennen, wenn ich mich gerade nicht komplett vertue (habe das include system von c++ noch nicht vollständig durchschaut)
Der Fehler liegt in den Zeilen:
MenuItem singlePlayer MenuItem localMultiPlayer MenuItem quitGame
-
In game.h steht include menuitem.h oder menustate.h?
-
#ifndef GAME_HPP #define GAME_HPP #include <iostream> #include <memory> #include <SFML\Graphics.hpp> #include "Gamestate.h" #include "MainMenuState.h" class Game { public: Game(); void Run(); bool isRunning(); bool running; sf::RenderWindow window; private: std::unique_ptr<Gamestate> CurrentState; }; #endif
-
Das geht so nicht.
#include ist reine Textersetzung.
Du kannst nicht in Datei A Datei B includen und in Datei B Datei A.
So sieht das aus, nachdem der Präprozessor die #include und Includeguard für MenuItem.h abgearbeitet hat (System-Header entfernt):class MainMenuState : public Gamestate { public: MainMenuState(); ~MainMenuState(); void HandleEvents(Game& game); void Update(Game& game); void Draw(Game& game); private: bool bSinglePlayerSelected, bLocalMultiPlayerSelected, bQuitGameSelected; sf::Font font; MenuItem singlePlayer; // eh, was zur Hölle ist MenuItem ??? MenuItem localMultiPlayer; // Header wurde nicht eingefügt, weil man sich gerade in MenuItem.h befindet MenuItem quitGame; // d.h. der Includeguard blockt das }; class Game { public: Game(); void Run(); bool isRunning(); bool running; sf::RenderWindow window; private: std::unique_ptr<Gamestate> CurrentState; }; using namespace std; class MenuItem { public: MenuItem(string, sf::Font, int, int, int); MenuItem(); ~MenuItem(); void setTitle(string); void setSize(int); void setFont(sf::Font); void setPosition(int, int); void setSelectedColor(sf::Color); void setDefaultColor(sf::Color); string getTitle(); int getSize(); int getPositionX(); int getPositionY(); sf::Color getSelectedColor(); sf::Color getDefaultColor(); bool checkIfHovered(Game& game); void draw(Game& game); private: sf::Font font; sf::Text text; sf::Color selectedColor, defaultColor; };
-
Gut, schonmal danke. Das der Fehler in die Richtung geht hatte ich ja bereits vermutet.
Wie könnte man das denn alternativ machen?
Mein Problem ist eben, dass ich zwar das Programmieren an sich halbwegs verstehe, aber mich nicht mit C++ konkret auskennt. Kannst du da ein Tutorial empfehlen?
-
Du brauchst in Game.h doch nur
#include <memory>
#include <SFML/Graphics.hpp>
#include "Gamestate.h"
-
Nur das includieren, was der Header (!) zum Übersetzen braucht.
Im einzelnen:
MainMenuState.h ist ok so, forward declarations würden zu weit führen.
MenuItem.h braucht kein Game.h, es braucht nur den Graphics Header von SFML (BTW: Kein using namespace in Headerdateien, böse!)
Game.h braucht kein iostream und kein MainMenuState.h.
-
In .cpp-Dateien kann man praktisch inkludieren, was man will, solange man .cpp-Dateien niemals in andere .cpp-Dateien (oder gar in .h-Dateien) inkludiert. So entstehen keine zyklischen includes.
Kniffliger ist die Sache mit .h-Dateien, denn die sollen (und werden) in andere inkludiert.
Hier muß man das beachten, was Nathan schreibt - indem man sich vorstellt, wie der Textstrom aus dem Präprozessor herauskommt und was demnach der Compiler zu sehen bekommt.
(- lernen zu denken wie ein Compiler ist ja sowieso keine schlechte Idee, wenn man C++ programmiert)ich vermeide zyklische Includes durch das Prinzip "nach einer Seite includieren, nach der anderen Seite deklarieren" - d.h. wenn A von B abhängt und B von A, dann schreibe ich in A.h "#include B.h" und in B.h
"class A;"
-
Nathan schrieb:
Nur das includieren, was der Header (!) zum Übersetzen braucht.
Im einzelnen:
MainMenuState.h ist ok so, forward declarations würden zu weit führen.
MenuItem.h braucht kein Game.h, es braucht nur den Graphics Header von SFML (BTW: Kein using namespace in Headerdateien, böse!)
Game.h braucht kein iostream und kein MainMenuState.h.Ich habe in MenuItem.h doch zwei Funktionen, die einen Parameter vom Typ Game haben, also muss ich doch Game includen?
bool checkIfHovered(Game& game); void draw(Game& game);Ohne das using namespace schmeißt mir Visual Studio aber Errors ohne Ende bei den strings entgegen, wie kann ich das denn umgehen?
Danke für die Hilfe!

-
Sorry hab die zwei nicht gesehen. Dann behalt das include. Oder informiere dich über forward declarations, dann brauchst du das auch nicht.
Zum Namespace: Dann machst du dasselbe wie mit dem Namespace von SFML, der heißt sf und die Elemente daraus prefixest du mit sf::, bei der Standardibliothek heißt der Namespace std und die Elemente prefixest du dann entsprechend mit std::.
-
Super, vielen Dank! Die ursprünglichen Fehler sind damit behoben.
Also kann ich mir grundsätzlich merken:
- So wenige includes in headern wie möglich
- Bei .cpp Datein sind die includes nicht so entscheidend (dürfen auch mal zuviele sein)
- Kein using namespace in headern
2 Fehler habe ich aber noch, die haben allerdings nicht umbedingt etwas mit den Ursprungsfehlern zu tun:
Error 2 error LNK2019: unresolved external symbol "public: __thiscall MenuItem::~MenuItem(void)" (??1MenuItem@@QAE@XZ) referenced in function __unwindfunclet$??0MainMenuState@@QAE@XZ$4 C:\Users\Michel\Documents\Visual Studio 2013\Projects\SFML Test\SFML Test\MainMenuState.obj Action Snake
Error 3 error LNK1120: 1 unresolved externals C:\Users\Michel\Documents\Visual Studio 2013\Projects\SFML Test\Debug\Action Snake.exe Action Snake
Die .cpp Datei der MainMenuState Klasse sieht folgendermaßen aus:
#include "MainMenuState.h" #include <iostream> MainMenuState::MainMenuState() :singlePlayer("Singleplayer", font, 45, 500.f, 350.f), localMultiPlayer("Local Multiplayer", font, 45, 500.f, 400.f), quitGame("Quit Game", font, 45, 500.f, 450.f) { //Load font and menu item text font.loadFromFile("assets\\fnt\\calibri.ttf"); } void MainMenuState::HandleEvents(Game& game) { //Handle all events sf::Event event; while (game.window.pollEvent(event)) { if (event.type == sf::Event::Closed) { game.window.close(); game.running = false; } } } void MainMenuState::Update(Game& game) { //Check if mouse is over menu item bSinglePlayerSelected = singlePlayer.checkIfHovered(game); bLocalMultiPlayerSelected = localMultiPlayer.checkIfHovered(game); bQuitGameSelected = quitGame.checkIfHovered(game); } void MainMenuState::Draw(Game& game) { //Renders the scene singlePlayer.draw(game); localMultiPlayer.draw(game); quitGame.draw(game); } MainMenuState::~MainMenuState() { //Destruktor of the class std::cout << "Menudestruktor wurde aufgerufen!" << std::endl; }
-
Smofe schrieb:
- So wenige includes in headern wie möglich
- Bei .cpp Datein sind die includes nicht so entscheidend (dürfen auch mal zuviele sein)
- Kein using namespace in headern
Ja, das ist soweit richtig. Zu viele includes in cpp sind natürlich auch nicht so schön, schaden aber auch nicht sonderlich (insbesondere nicht bei Projekten deiner Größe).
2 Fehler habe ich aber noch, die haben allerdings nicht umbedingt etwas mit den Ursprungsfehlern zu tun:
Error 2 error LNK2019: unresolved external symbol "public: __thiscall MenuItem::~MenuItem(void)" (??1MenuItem@@QAE@XZ) referenced in function __unwindfunclet$??0MainMenuState@@QAE@XZ$4 C:\Users\Michel\Documents\Visual Studio 2013\Projects\SFML Test\SFML Test\MainMenuState.obj Action Snake
Error 3 error LNK1120: 1 unresolved externals C:\Users\Michel\Documents\Visual Studio 2013\Projects\SFML Test\Debug\Action Snake.exe Action Snake
Irgendwas mit "unresolved external symbol" oder "undefined reference" heißt immer: du hast eine Funktion deklariert, aber nirgends definiert. In diesem Fall ist das der Destruktor der MenuItem Klasse. Da du in den Destruktoren aber eh nur (unnötige) Logausgaben machst, kannst du die auch weglassen.
Nur so aus Neugier: Kannst du mal das Tutorial verlinken, das scheint richtig gut zu sein, dass es dir std::unique_ptr beibringst.
Zum weiteren Lernen von C++: Da du scheinbar schon Erfahrungen im Programmieren hast, ist The C++ Programming Language vom Erfinder der Sprache selber oft empfohlen werden:
The C++ Programming Language | ISBN: 9780321563842
Ich selber kenne es nicht, aber es soll die grundlegenden Grundlagen nicht detailliert behandlen, sondern eher die Sprache C++ vorstellen.
-
Schau dir mal nebenbei die SFML Engine von den Entwiklern an. Der Code ist aus dem Buch: http://www.amazon.de/SFML-Game-Development-Jan-Haller/dp/1849696845
Code: https://github.com/LaurentGomila/SFML-Game-Development-Book
-
In deinem Eröffnungsbeitrag wird in Zeile 14 ein selbstgeschriebener Destruktor deklariert. Den implementierst du aber anscheinend nirgendwo (oder an einem Ort, den der Linker nicht finden kann). Brauchst du überhaupt einen selbstgeschriebenen Destruktor? Falls ja, wäre deine Klasse höchstwahrscheinlich unvollständig, da du dann die Regel der großen Drei verletzen würdest. Das sieht mir doch eher danach aus, als würde der compilergenerierte Destruktor vollständig ausreichen (wie es normal ist) und du kannst dir die Deklaration einfach komplett sparen.
Das gleiche gilt höchstwahrscheinlich auch für den selbstgeschriebenen Standardkonstruktor in der Zeile davor, bloß rufst du diesen anscheinend sowieso nirgendwo auf.
Wenn dir irgendein Lehrbuch beigebracht haben sollte, dass du immer eigene Destruktoren und Standardkonstruktoren schreiben solltest, selbst wenn diese dann leer sind: Ein Fall fürs Altpapier.
-
Ja, es lag tatsächlich an dem Destruktor.
Vielen Dank! Ihr habt mir wirklich sehr geholfen. Ich werde mir die beiden Bücher mal angucken, vielleicht befindet sich ja auch eins davon in der Bücherei vorort

Ein Lehrbuch hat mir hier nichts beigebracht - das war ja auch das Problem. Jetzt klappt jedenfalls alles!

Einen schönen Abend noch.
Edit: Die Konstruktoren sind alle mit Code befüllt - nur der Destruktor war leer
