Referenzübergabe Objekte einer Klasse [gelöst]



  • Hallo, ich verzweifle hier an einer sicherlich völlig einfachen Sache befürchte ich. Bin an sich sehr geduldig und habe auch etliche Foreneinträge hinter mir, aber ich bin wohl doch zu doof 😕 ….

    Ich möchte dem Objekt E der Klasse ENEMY gerne eine Referenz des Objekts P der Klasse PLAYER zur weiteren "Nutzung" übergeben.

    So sieht mein Code aus, der aber folgende Fehlermeldung bei E.RP(&P); auswirft:

    • C2664 "int ENEMY::RP(int&)" : Konvertierung von Argument 1 von "PLAYER" in "int&" nicht möglich

    Klasse PLAYER

    #pragma once
    class PLAYER
    {
    public:
    	PLAYER(int x, int y) : px(x), py(y) {};
    	~PLAYER();
    
    private:
    	int pleben;
    };
    
    

    Klasse ENEMY

    
    #pragma once
    class ENEMY
    {
    public:
    	ENEMY(int x, int y) : ex(x), ey(y) {};
    	~ENEMY();
    
    	int RP(int &refObj);
    
    private:
    
    	int eleben;
    	int epunkte;
    };
    

    Hauptprogramm (main.cpp)

    #include "pch.h"
    #include <iostream>
    #include <Windows.h>
    #include "ENEMY.h"
    #include "PLAYER.h"
    
    PLAYER P(20,5);
    PLAYER* Ppointer;
    ENEMY E(5,20);
    
    
    int main()
    {
    
    Ppointer = &P;
    
    E.RP(&P);
    
    	Sleep(100000);
    
    }
    

    Danke für Eure Hilfe!!!



  • Warum denn ein int &?



  • Gute Frage ☹ … was wäre denn sinniger oder überhaupt richtig 😕 in diesem Zusammenhang?! Vielleicht sehe ich auch den Wald vor lauter Bäumen nicht ...



  • Wenn du eine Referenz auf einen PLAYER übergeben willst, dann wohl PLAYER&? Ein int& wäre doch eine Referenz auf einen int. Ist ein PLAYER dasselbe wie int?

    Wenn ich den PLAYER im ENEMY speichern würde, würde eher ein Zeiger in Frage kommen, da du eine Member-Referenz nicht ändern kannst.

    Die Frage ist aber immer: Wem gehört der Spieler? Kann der Spieler sterben, bevor der Freind stirbt?

    Solange du den Player nur in der RP-Funktion nutzt, ist (wenn möglich: const) PLAYER& eine gute Idee als Parameter.



  • @Kloeterkong sagte in Referenzübergabe Objekte einer Klasse:

    PLAYER P(20,5);
    PLAYER* Ppointer;
    ENEMY E(5,20);
    

    Lass globale Variablen bitte am besten gleich wieder bleiben.



  • Wenn ich das jetzt richtig verstanden habe, dann müsste das ...

    int RP(int &refObj);
    

    so aussehen ...?!

    int RP(PLAYER &refObj);
    

    und analog dazu natürlich in der ENEMY.cpp ... dazu die PLAYER.h in ENEMY.h inkludieren ...

    Wenn ich dann die Methode RP aus der Klasse ENEMY aufurfe, dann meldet der Compiler ...

    ENEMY::RP: Funktion akzeptiert keine 1 Argumente und überladene Memberfunktion nicht in ENEMY gefunden, wobei diese doch da ist?!

    Ich übergebe doch das Argument in Form einer/der Referenz "&P"?

    @wob: Die globale Variablendefinition habe ich jetzt mit in die main gepackt - danke für den Tipp



  • @Kloeterkong sagte in Referenzübergabe Objekte einer Klasse:

    Wenn ich das jetzt richtig verstanden habe, dann müsste das ...

    int RP(int &refObj);

    so aussehen ...?!

    int RP(PLAYER &refObj);

    Ja.

    dazu die PLAYER.h in ENEMY.h inkludieren ...

    Ja oder besser forwarden. Der Rest ist unverständlich sollte aber so aussehen:

    Player player(20,5);
    Enemy enemy(5,20);
    enemy.RP(player);
    

    (hab mich geweigert die Klassen komplett groß zu schreiben, sollte trotzdem verständlich sein)



  • @Kloeterkong sagte in Referenzübergabe Objekte einer Klasse:

    , dann meldet der Compiler ...
    ENEMY::RP: Funktion akzeptiert keine 1 Argumente und überladene Memberfunktion nicht in ENEMY gefunden, wobei diese doch da ist?!

    Nein, das meldet der Compiler bestimmt nicht. Zumindest nicht genau so. Bitte copy/paste der Fehlermeldung.

    Ich übergebe doch das Argument in Form einer/der Referenz "&P"?

    &P ist ein Pointer auf P. Wenn du enemy.RP(&P) beim Aufruf nutzt, musst du einen Player* in der Argumentliste haben. Wenn da Player& steht, rufst du enemy.RP(P) auf.

    Schau dir am besten nochmal an, wie Pointer und Referenzen funktionieren.

    @wob: Die globale Variablendefinition habe ich jetzt mit in die main gepackt - danke für den Tipp

    Huch? Dazu habe ich doch gar nichts geschrieben?! (das war @Swordfish). Aber @Swordfish hat natürlich recht: keine globalen Variablen!

    PS: Habe mich @Jockelx angeschlossen und die durchgehende Großschreibung der Klassennamen verweigert.



  • Jetzt passt es! Was ich vergessen habe oder eher auch nicht wusste ist die Sache mit dem "forwarden", das habe ich jetzt in der ENEMY.h gemacht (hoffe passt so!?). Die Klassen habe ich auch anders geschrieben, nix mehr komplett groß 🙂 .... Mit der Erklärung bzgl. Referenzen und Pointer hat auch geholfen, da fehlt mir noch der Umgang und die Routine 🙂 … irgendwann fängt man dann an, an sich zu zweifeln und verzweifelt dann irgendwann und dreht nur noch Sachen im Code hin und her … natürlich Müll ...

    So sieht das jetzt aus …

    ENEMY.h

    #pragma once
    class Player;
    class Enemy
    {
    public:
    
    	Enemy(int x, int y) : ex(x), ey(y) {};
    	~Enemy();
    
    	int RP(Player& p);
    
    private:
    
    	int eleben;
    	int ex;
    	int ey;
    	
    };
    

    ENEMY.cpp

    #include "pch.h"
    #include "ENEMY.h"
    #include "PLAYER.h""
    #include <iostream>
    #include <string.h>
    
    Enemy::~Enemy()
    {
    }
    
    int Enemy::RP(Player& p)
    {
    
    	std::cout << "ENEMY.cpp P" << &p << std::endl;
    	return 0;
    }
    

    PLAYER.cpp

    #include "pch.h"
    #include "PLAYER.h"
    #include <iostream>
    #include <string.h>
    
    Player::~Player()
    {
    }
    

    Player.h

    #include "pch.h"
    #include "PLAYER.h"
    #include <iostream>
    #include <string.h>
    
    Player::~Player()
    {
    }
    

    main.cpp

    #include "pch.h"
    #include <iostream>
    #include <Windows.h>
    #include "ENEMY.h"
    #include "PLAYER.h"
    
    
    int main()
    {
    Player P(20, 5);
    Enemy E(5, 20);
    
    std::cout << "main P: " << &P << std::endl;
    std::cout << "main E: " << &E << std::endl;
    
    E.RP(P);
    
    	Sleep(100000);
    }
    

    Ausgabe:

    main P: 0073FCEC
    main E: 0073FCD8
    ENEMY.cpp P 0073FCEC

    Danke für Eure Hilfe, und auch Dir natürlich Swordfish!! Verbesserungsvorschläge nehme ich gerne entgegen … danke ...

    Der nächste Schritt ist jetzt, dass ich über die Referenz bzw. Adresse versuche was am Objekt P "zu ändern", z.B. px oder py ...


  • Mod

    @Kloeterkong sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    Verbesserungsvorschläge nehme ich gerne entgegen … danke ...

    • Deine Namensgebung. Nicht gut. Gar nicht gut. Wird dir schon bald Schwierigkeiten machen. Macht dir vielleicht sogar jetzt schon Schwierigkeiten.
    • Du musst echt dringend nochmal angucken, wie das mit dem objektorientiertem Design geht. Habe ich schon im anderen Thread gesagt. Ist natürlich kein leichtes Thema, das man von einem Tag auf den anderen Lernen kann.
    • Lauter technische Kleinigkeiten
      • Es heißt <string>, nicht string.h>
      • Unnötige leere Destruktoren sind unnötig
      • mehr, das ich nicht aufzähle.


  • Ja, das ist das Problem wenn man das im Selbststudium versucht zu lernen, neben sich ein paar Bücher, aber auch da gibt es dann unterschiede. Zähl ruhig auf wenn es nicht zu viel Umstände oder Aufwand macht, will es ja lernen, und dann auch anständig.



  • Dann zähl ich mal ein paar Sachen auf:

    Zur Namensgebung und Variablen:

    • Warum ist erleben ein int? Kann man das zählen, kann man damit rechnen? Was soll erlebt werden? Warum wird die Variable nirgends verwendet, zumindest initialisiert.
    • Was soll ex und ey sein?
    • Was soll RP heißen? Warum gibt die Funktion einen int zurück?
    • Player P und Enemey E, was ist wenn du mehr Spieler und Feinde hast? Upper Case Variablen Namen sind sehr untypisch.
    • Warum ist Enemy englisch und erleben deutsch?

    Andere Sachen:

    • Wenn du eine Referenz an eine Funktion übergibst, diese aber nicht veränderst, mach eine const Referenz daraus. Damit ist für den Compiler und alle die deinen Code lesen sofort sichtbar, dass sich da nichts ändert.
    • Warum gibst du Adressen von Variablen aus?
    • Bist du dir sicher, dass du weißt, was Precompiled Header sind und das du die verwenden willst?
    • Warum wird die windows.h inkludiert.
    • Upper Case Dateinamen sind auch ungewöhnlich und nicht ungefährlich. So ignoriert Windows Upper und Lower Case, während Linux Distributionen das beachten.
    • Warum inkludiert Player.h und Player.cpp iostream und string
    • Vlt bin ich grade blind, aber wo brauchst du string überhaupt?
    • Ach, und ich mag Sleeps nicht um das Programm künstlich offen zu halten. Starte es aus der Konsole, da bleibt die Ausgabe stehen, oder je nach IDE gibt es auch Möglichkeiten, Programme aus der IDE so zu starten, dass die Konsole offen bleibt.
      Das hat keinen Anspruch auf Vollständigkeit, sind aber schon mal ein paar Hinweise, wie das ein oder andere besser gehen könnte.


  • @Schlangenmensch sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    Warum ist erleben ein int? Kann man das zählen, kann man damit rechnen?

    Weil da nicht erleben, sondern eleben steht. Es scheint, dass alle Member-Variablen hier mit einem "e" geprefixt sind (warum auch immer). Somit ist es die Anzahl der Leben des Spielers. Also ist int als Typ ok.

    Also Rat an @Kloeterkong: keine unnötigen Prefixes, schon gar nicht "e". In manchen Codestyles findest du Member mit "f" oder "m_" geprefixt oder die Member haben einen "_" als Postfix. Ich würde es erstmal ohne Spezialkennzeichnung versuchen.



  • @wob sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    Weil da nicht erleben, sondern eleben steht. Es scheint, dass alle Member-Variablen hier mit einem "e" geprefixt sind (warum auch immer). Somit ist es die Anzahl der Leben des Spielers. Also ist int als Typ ok.

    Oh... Augen aufmachen hilft 😃



  • @wob sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    In manchen Codestyles findest du Member mit "f" ..." geprefixt

    Habe ich noch nie gesehen. Wofür steht das f?


  • Mod

    Was er hier gemacht hat, ist alle Member einer Klasse mit einem Klassenkürzel zu prefixen. "eleben" für "enemy leben", "pleben" für "player leben". Was Unsinn ist, weil die Klassenzugehörigkeit schon eindeutig ist durch die Zugehörigkeit zur Klasse 😉
    Das war einer der Gründe, warum Namenskonvention als allererstes auf meiner Kritikliste stand. Da schwingt natürlich auch meine Beobachtung mit rein, dass Objektorientierung wahrscheinlich nicht verstanden wurde, denn wenn man den Sinn und Zweck von Klassen verstanden hätte, dann käme man nie auf diese Konvention.



  • @Jockelx sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    @wob sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    In manchen Codestyles findest du Member mit "f" ..." geprefixt

    Habe ich noch nie gesehen. Wofür steht das f?

    Musste ich jetzt googlen. Für "field". War tatsächlich die erste Konvention, die ich kennengelernt habe. Das ist in Delphi der Standard (und ist auch so in der "Standardbibliothek" durchgezogen - guck z.B. http://docwiki.embarcadero.com/Libraries/Tokyo/de/System.Classes.TList.Count -> gelesen wird hier "FCount"). Auch große C++-Projekte wie ROOT verwenden diese Konvention.

    Irgendwann später habe ich dann mal Qt-Programme gesehen. Die waren voll mit "m_".

    Und das Postfix "_" habe ich auch schon in diversen Real-World-Projekten gesehen.



  • @wob
    Interessant mit dem 'f'.
    'm_', 'm' und '_' kenne ich natürlich auch und wenn ich mich richtig erinnere hatte ich sogar noch nie ein Projekt, wo Member nicht geprefixt wurden.
    Das Member-Prefix (und nur das!) finde ich übrigens im Gegensatz zu dem überwiegendem Rest hier auch nicht schlimm - oft sogar hilfreich.
    Wahrscheinlich Gewohnheit.



  • Oh Gott, was habe ich losgetreten 🙂 … an all den Punkten werde ich arbeiten und hoffe das man es auch irgendwann sehen oder lesen kann. Für mich ist existenziell wichtig, dass es solche - verbessere DIESE Community - gibt, denn das hilft einem wirklich weiter, weil man auf Lösungen hingewiesen wird und keine präsentiert werden, man beschäftigt sich mehr mit dem Problem und dadurch verbessert sich der Umgang mit C++ … zumindest meine Erfahrung.

    Das mit den Objekten habe ich glaube aber verstanden, die ja dann die Instanz der Klassen sind, die wiederum als Art Schablone dienen oder Prototypen. Die Member- oder auch Methodenbezeichnungen (eleben ist wirklich "enemy leben", könnte natürlich auch einfach nur leben heißen, da gemäß Kapselung ja auch nur da gültig 🙂 ) sind natürlich nicht optimal, sind aber auch nur so gewählt, dass ich selbst erst einmal beim lesen sehe was ich wo mache oder mit was ich gerade hantiere. Die Ausgabe am Ende dient einfach meiner Kontrolle.

    Kurzum: Ich versuche C++ erst einmal in vielen kleinen Programmen zu erlernen, dieses war eines davon.


  • Mod

    @Kloeterkong sagte in Referenzübergabe Objekte einer Klasse [gelöst]:

    Das mit den Objekten habe ich glaube aber verstanden, die ja dann die Instanz der Klassen sind, die wiederum als Art Schablone dienen oder Prototypen. Die Member- oder auch Methodenbezeichnungen (eleben ist wirklich "enemy leben", könnte natürlich auch einfach nur leben heißen, da gemäß Kapselung ja auch nur da gültig 🙂 ) sind natürlich nicht optimal, sind aber auch nur so gewählt, dass ich selbst erst einmal beim lesen sehe was ich wo mache oder mit was ich gerade hantiere. Die Ausgabe am Ende dient einfach meiner Kontrolle.

    Es geht eigentlich gar nicht so sehr darum, wie Klassen und Objekte technisch funktionieren (das ist aber natürlich auch wichtig), sondern dass man bei der Entwicklung schon objektorientiert denkt. Welche Objekte gibt es? Was sind ihre Eigenschaften und Invarianten? Wie interagieren sie? Und das halt nicht im Nachhinein irgendwie zusammen gefrickelt, sondern von Vornherein sinnvoll geplant.

    Das ist natürlich nicht ganz einfach und kann man nicht mal eben so in einem Forenbeitrag erklären, aber es erwartet auch niemand von einem Anfänger, dass er das sofort richtig kapiert.


Anmelden zum Antworten