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

AintLarry

Frischling

  • »AintLarry« ist der Autor dieses Themas

Beiträge: 58

Wohnort: Hamburg

Beruf: Kaufmann für Versicherungen und Finanzen

  • Private Nachricht senden

1

21.08.2016, 23:27

[C++] Setter Methode eines Objektes verändert die entsprechende Variable nicht.

Hallo Leute,

ich habe ein kleines Problem.

In meinem Objekt "MapCoordinate" habe ich eine int-Variable welche ich nun über einen Setter ändern will.
Der Zugriff erfolgt über einige andere Objekte.

Ich befinde mich in der Klasse "MapGenerator" und will über die Objekte "Map" -> "MapLayer" -> "MapCoordinate" die Variable ändern.

Es kommt keinerlei Fehlermeldung, allerdings ist die Variable unverändert, wenn ich Sie über den Getter aufrufe.

Hier nun die entsprechenden Code Ausschnitte:

MapCoordinate.h

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
#ifndef MAPCOORDINATE_H
#define MAPCOORDINATE_H

class MapCoordinate
{
public:
    MapCoordinate();

    int getUndergroundID();
    void setUndergroundID(int i);

    int getFunctionID();
    void setFunctionID(int i);

    int getXCoord();
    void setXCoord(int i);
    int getYCoord();
    void setYCoord(int i);

private:

    int undergroundID;
    int functionID;
    int x;
    int y;


};

#endif


MapCoordinate.cpp (Ausschnitt)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
int undergroundID;
    // 0 = undefined, 1 = wall, 2 = room, 3 = floor, 4 = water, 5 = puddle

int MapCoordinate::getUndergroundID()
{
    return undergroundID;
}
void MapCoordinate::setUndergroundID(int i)
{
    undergroundID = i;
}


MapLayer.cpp (Ausschnitt) enthält zweidiemensionales Array aus MapCoordinate-Objekten

C-/C++-Quelltext

1
2
3
4
MapCoordinate MapLayer::getCoord(int x, int y)
{
    return progressLayer[x][y];
}


Map.cpp (Aussschnitt) enthält Array aus MapLayer-Objekten

C-/C++-Quelltext

1
2
3
4
MapLayer Map::getLayer(int i)
{
    return progressMap[i];
}


Versuchter Zugriff (MapGenerator.cpp)

C-/C++-Quelltext

1
2
        currentLayer.getCoord(3, 3).setUndergroundID(1);
        std::cout << "ID" << currentLayer.getCoord(3, 3).getUndergroundID() << std::endl;


Obwohl ich die ID auf 1 ändere, gibt der Getter die 0 aus.

Ich habe leider überhaupt keine Idee woran es liegen kann. Ich nehme nur an, dass ich einen Fehler mit Zeiger oder nicht Zeiger gemacht habe.

Hat jemand einen Ansatz?

Danke.

Henrik

Julién

Alter Hase

Beiträge: 717

Wohnort: Bayreuth

Beruf: Student | Hilfswissenschaftler in der Robotik

  • Private Nachricht senden

2

21.08.2016, 23:38

Wie initialisierst du "progressLayer"?
Außerdem: Die Indexierung von Arrays beginnt bei 0 - spricht das erste Element hat den Index 0.
I write my own game engines because if I'm going to live in buggy crappy filth, I want it to me my own - Ron Gilbert

3

22.08.2016, 01:20

GetCoord gibt eine Kopie von progressLayer[x][y] zurück, du benötigst aber eine Referenz/Adresse darauf.
Du veränderst bei currentLayer.getCoord(3, 3).setUndergroundID(1); nur die undergroundID der Kopie von progressLayer[x][y].
Die Werte des eigentlichen Arrays bleiben dabei aber unverändert.

So müsste das ganze aussehen:

C-/C++-Quelltext

1
2
3
4
MapCoordinate &MapLayer::getCoord(int x, int y) //<= Gibt eine Referenz auf die Koordinate zurück, ohne '&' würde es lediglich den Wert dessen zurückgeben!
{
    return progressLayer[x][y];
}


Zu beachten ist das kaufmännische Und (&). Damit gibst du dann, dass nicht der Wert, sondern die Speicheradresse zurückgegeben wird.
Mehr kannst du beispielsweise hier nachlesen.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Tucker« (22.08.2016, 01:26)


Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

4

22.08.2016, 10:06

Lieber MapCoordinate& MapLayer::.... Dadurch ist offensichtlich, dass sich die Referenz auf MapCoordinate bezieht.
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

22.08.2016, 10:13

Ich würde erstmal hinterfragen, wieso alle diese Member private sein sollen, wenn die Klasse effektiv doch eh nur ein Datencontainer ist. Wieso nicht einfach ein struct und fertig?

Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

6

22.08.2016, 11:23

Was dot meint: In Java (Aus dem Umfeld kommst du ja, soweit ich weiß) werden Membervariablen oft mittels Gettern und Settern gekapselt. In manchen Fällen macht das Sinn (Manche Frameworks nutzen dann Reflection, oder Subclassing, um den jeweiligen Methoden neue Funktionalitäten hinzuzufügen oder die Member dynamisch ändern zu können. Spring und Hibernate arbeiten beispielsweise so), in vielen Fällen aber nicht.

Da C++ nicht über Reflection verfügt (Ja, es gibt Möglichkeiten über Templates, das lasse ich hier jetzt aber raus), geht man meist nach der einfachen Regel vor: Müssen beim Zugriff auf Membervariablen zusätzliche Aktionen ausgeführt werden? Wenn ja: Getter und/oder Setter erstellen. Wenn nein: Als public deklarieren. Optional, wenn alles an deiner Klasse im public scope liegt, kannst du aus der Klasse auch ein Struct machen. Damit sparst du dir dann aber nur das public:
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

AintLarry

Frischling

  • »AintLarry« ist der Autor dieses Themas

Beiträge: 58

Wohnort: Hamburg

Beruf: Kaufmann für Versicherungen und Finanzen

  • Private Nachricht senden

7

22.08.2016, 17:41

Hallo,

die Klasse habe ich der Übersicht halber erstellt, so macht der Code für mich Sinn und ich kann alles gut nachvollziehen.
Ob nun Setter/Getter oder die Variablen als public deklarieren ist meines Erachtens nach eine Geschmackssache. Ich sehe so viel schneller, was mein Code grade macht, das ich es gewöhnt bin.

Wenn ich das richtig verstehe, ist es für mein Beispiel ja auch nicht Vorteilhafter als Getter und Setter zu benutzen, oder?

Ich habe euren o.g. Tipp mit der Referenz nun umgesetzt. Dieser Teil funktioniert nun.

Wenn ich das gesamte MapObjekt aber in dann in eine weitere void übergebe, wirft er mir wieder die ungeänderten Daten hinaus. Wo mögich habe ich den Code nun schon auf Referenzen umgestellt.

C-/C++-Quelltext

1
2
3
4
5
6
7
processMap = new Map(width, height, numOfLayers);

    for (int i = 0; i < processMap->getNumOfLayers(); ++i)
    {
            currentLayer.getCoord(3, 3).setUndergroundID(1);
        }
   printMap(processMap);


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
void MapGenerator::printMap(Map *m)
{
    for (int i = 0; i < m->getNumOfLayers(); ++i)
    {
        MapLayer printLayer = m->getLayer(i);

        sf::Image image;
        image.create(printLayer.getWidth(), printLayer.getHeight(), sf::Color::White);

        for (int w = 0; w < printLayer.getWidth(); w++)
        {
            for (int h = 0; h < printLayer.getHeight(); h++)
            {
                std::cout << w << " x " << h << " ID " << printLayer.getCoord(w, h).getUndergroundID() << std::endl;

                if (printLayer.getCoord(w, h).getUndergroundID() == 0)
                {
                    image.setPixel(w, h, sf::Color::White);
                }
                if (printLayer.getCoord(w, h).getUndergroundID() == 1)
                {
                    image.setPixel(w, h, sf::Color::Black);
                }
            }
        }

        std::string num = std::to_string(i);

        image.saveToFile("savedMaps/Map_Layer_" + num + ".png");

    }


Die Methode befindet sich in der selben Klasse wie der Aufruf. Ich habe euch den Quellcode auf das Wesentliche gekürzt.
Ich habe heute schon mehrmals das Kapitel über Referenzen und Zeiger aus meinem C++Buch gelesen, aber ich finde meinen Fehler nicht.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

8

22.08.2016, 17:57

Es wurde dir ja auch nicht gesagt du sollst keine Klasse benutzen und mit einzelnen Variablen rum hantieren sondern dass du dir die getter und setter sparen kannst und deine Attribute public machen kannst. Und da kann man dann wenn man möchte structs benutzen weil die automatisch alles public machen. Guck vielleicht einfach mal was die Unterschiede zwischen struct und class sind. Ansonsten würde ich das Thema hier gern abbrechen. Wenn dich interessiert warum hier von settern abgeraten wird und warum dot meint dass die böse sind dann kannst du hier im Forum die Suchfunktion benutzen. Es gibt mittlerweile mehrere Threads zu diesem Thema. Nimelrian hat ja schon ein wenig dazu gesagt.
Was dein Problem angeht, guck mal was ein Copyconstructor ist und wie man diesen entfernen kann.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

AintLarry

Frischling

  • »AintLarry« ist der Autor dieses Themas

Beiträge: 58

Wohnort: Hamburg

Beruf: Kaufmann für Versicherungen und Finanzen

  • Private Nachricht senden

9

22.08.2016, 18:17

Hallo Schorsch,

mir wurde die Frage gestellt, warum ich den Code so geschrieben habe, wie ich es getan habe, und die habe ich versucht schlüssig zu beantworten und zu begründen.

Ich finde zu Copyconstructor zich Beiträge allerdings nur, wie diese einzusetzen sind. Nicht aber wie ich diese entferne.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

10

22.08.2016, 18:40

Guck mal hier. Stichworte die ich genutzt habe waren "delete copy constructor". Google ist ein wichtiges und mächtiges Werkzeug ;)
Warum das ganze? löschst du den CC bedeutet das eine Instanz dieser Klasse kann nicht mehr kopiert werden. Soll heißen wenn du eine Klasse hast bei der du weißt dass sie nicht kopiert werden soll sondern nur per Referenz übergeben werden kann, dann kannst und solltest du ihren Copyconstructor löschen. Versuchst du dann aus versehen ein Instanz zu kopieren gibts ne Fehlermeldung vom Compiler. Damit solltest du fix sehen an welcher Stelle dein Fehler ist.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

Werbeanzeige