Membervariable über Memberfunktion initialisieren



  • @titan99_ sagte in Membervariable über Memberfunktion initialisieren:

    Wenn die lokale Variable des Funktionsparameters den gleichen Namen hat, wie die zu initalisierende Membervariable, klappt es bei aobject.Set0(1);nicht. Wie soll ich den Funktionsparameter umbenennen? Oder ist es besser mit dem this-Zeiger die Membervariable in die Memberfunktion zu "holen"?

    Ich persönlich verwende den Prefix m_ für Membervariablen. Dadurch heisst die Membervariable dann m_size und es gibt keine Kollision mehr. Finde ich besser als überall this->size zu schreiben.

    Und normalerweise einfach nur size zu schreiben, aber dann selektiv auf this->size auszuweichen wo es nötig ist, finde ich am schlimmsten (weil verwirrend).


  • Gesperrt

    @hustbaer sagte in Membervariable über Memberfunktion initialisieren:

    Und normalerweise einfach nur size zu schreiben, aber dann selektiv auf this->size auszuweichen wo es nötig ist, finde ich am schlimmsten (weil verwirrend).

    Die "Selektion" ist ja dann darauf beschränkt, wenn einer Membervariable ein Wert direkt über einen Funktionsparameter und ausserhalb des Konstruktors zugewiesen wird (Oder beim Konstruktor ausserhalb der initializer list) .

    Danke auch für die Erklärung von Deklaration, Definition, Initialisation und Zuweisung. 🤔



  • Ich nenne so einen Parameter nicht wie den Member, maximal ähnlich. Erstmal muss ich im öffentlichen Interface nicht verraten, wie meine privaten Variablen heissen. Zweitens wird der Wert vlt. gar nicht 1:1 übernommen, damit wäre ja auch jegliche Kapselung ausgehebelt. Auf so ein size würde ja in vielen Fällen erstmal ein clamp gemacht werden.


  • Gesperrt

    @tggc

    void CircleShape::SetResolution(size_t resolution)
    {
    	this->resolution = resolution;
    	ResizeBuffer(resolution * 3);
    }
    

    Es handelt sich im konkreten Fall um eine "Hilfsvariable":

    for (auto index = 0U; index < resolution; ++index) {}
    
    float step = 2.f * glm::pi<float>() / static_cast<float>(resolution); 
    

    sonst müsste jedesmal durch 3 teilen:

    for (auto index = 0U; index < vertices.size() / 3U; ++index) {}
    
    float step = 2.f * glm::pi<float>() / static_cast<float>(vertices.size() / 3U);
    


  • D.h. du gibst mir recht, weil dein Code crashed?


  • Gesperrt

    Weil es kein clamp hat? Also die untere Grenze wäre dann 3. Aber würde eher eine Fehlermeldung ausgeben lassen, als dass klammheimlich der Wert geändert wird. Zudem ist es eine abgeleitete Klasse und in der jetzigen Phase halte ich es für vorteilhaft, alle Eingaben zuzulassen. Auch kenne mich mit exceptions und asserts usw. auch nicht gut aus. Und wenn, würde ich nicht bei abgeleiteten Klassen anfangen diese einzufügen. Hinzu kommt, dass eine "Vertex-Pumpe" involviert ist, die möglichst effizient und einfach sein soll.

    Edit: Die untere Grenze wäre bei den vertices 3, bei der resolution 1.



  • Na gut. Dann frag halt nicht, wenn du nur deine Meinung bestätigt haben möchtest selbst wenn du Crashes und undefinierstes Verhalten programmierst...


  • Gesperrt

    Also eigentlich hoffte ich auf ein brainstorming, was ja geschah.

    • Habe prefix bzw. suffix, postfix als Antworten bekommen, darunter z.B. das prefix m_ bei privaten(?) Membervariablen.
    • Zusätzlich Deklaration, Definition, Initialisation und Zuweisung bei Variablen.
    • Most Vexing Parse wegen den Klammern im Zusammenhang mit dem Konstruktor.
    • int main() braucht nicht unbedingt ein return statement, wenn 0 zurückgegeben werden soll und dies hat nicht mit void main() zu tun, weil es angeblich im Standard so gefordert wird.
    • Verschiedene Namensfindungen für Variablen und entsprechende Gründe.

    Auf dieser Grundlage kann ich dann entscheiden, wie ich die Membervariable und den Funktionsparameter nennen kann. Gut möglich, dass undefiniertes Verhalten geschieht oder es näher am undefinierten Verhalten ist. Aber falls der Code bei manchen Eingaben crashed, möchte ich wissen, wo der Code crashed. Wenn ich den crash mal hier mal dort durch Eingabebeschränkungen in abgeleiteten Klassen verhindere, finde ich eventuell den Grund in der Basisklasse nicht mehr.
    Es ist vielleicht ein hinkender Vergleich, aber ein Bildhauer fängt auch nicht mit den Feinarbeiten an. Würde er das, müsste er bei groben Änderungen die Feinarbeiten wiederholen und hätte so mehr Arbeit.

    Es passt zwar nicht mehr zum Thementitel, aber wenn ich die Memberfunktion SetResolution privat "mache"(?), ergeben sich ohne weitere Umwege bereits Einschränkungen die crashes verhindern. Behalte statische und dynamische CircleShapes in einer Klasse, ohne das beim statischen CircleShape der Buffer bei jeder Draw-Anweisung neu geladen werden muss. Bei der dynamischen Draw-Anweisung des CircleShape kann aber die resolution geändert werden und muss nicht fix bei 64 bleiben, wie derzeit im Konstruktor zugewiesen.

    So habe ich auf einfache Weise dynamische und statische CircleShape in einer Klasse. Möchte ich in der Basisklasse zum OpenGL Interface etwas ändern, muss ich höchstens sehr wenig in den abgeleiteten Klassen ändern. Möchte ich einen geometry-shader irgendwann implementieren oder den Buffer als Pointer holen, so kann ich irgendwann bei allen vier oder mehr Implementierungen die Performance vergleichen, was ich aber im Moment nicht wichtig finden.

    Sollte der Code wegen identischen Variablennamen der Membervariable und des Funktionsparameters crashen, so kann ich jederzeit der Membervariable ein m_ prefix voranstellen. Zudem kapsle ich auch nicht alles, ein Teil der Basisklasse ist protected.

    @tggc sagte in Membervariable über Memberfunktion initialisieren:

    Zweitens wird der Wert vlt. gar nicht 1:1 übernommen, damit wäre ja auch jegliche Kapselung ausgehebelt.

    Wieso wäre dann die Kapselung ausgehebelt?



  • @tggc sagte in Membervariable über Memberfunktion initialisieren:

    Zweitens wird der Wert vlt. gar nicht 1:1 übernommen, damit wäre ja auch jegliche Kapselung ausgehebelt.

    Wieso wäre dann die Kapselung ausgehebelt?

    Wenn du eine private Variable x hast, der man dank der Set Funktion jeden Wert zuweisen kann, dann ist die nur noch auf dem Papier private. Du müsstest dann bei jeder Verwendung von x testen, ob da nicht Unsinn drin steht und falls doch hast du keine Ahnung warum. Daher ist auch der Vergleich mit einem Bildhauer an der Stelle IMHO nicht sinnvoll. Objektorientierte Programmierung ist extra dafür ausgelegt, das du deine Klasse mit dem Member x nur von "innen" checken musst, also sich alle Fehler die in x Unsinn reinschreiben innerhalb der Klasse befinden und nicht sonstwo im Code. Wenn man diesen Grundsatz erst mal verstanden hat, wird einem auch klar, das es eine wichtigen Unterschied von Member x und Parameter x gibt, der weit über den Namen hinausgeht.


  • Gesperrt

    @tggc

    Danke für die Erklärung (Entschuldigung für meine schlechte Laune heute morgen 😣 ).

    Also SetResolution ruft auch ResizeBuffer der Basisklasse auf. Dort wird dann mit glBufferData(GL_ARRAY_BUFFER, buffersize, nullptr, GL_STREAM_DRAW) die Buffergrösse festgelegt, soweit ich weiss aber auch der Inhalt "gelöscht" bzw. "überschrieben" (Deshalb übergebe ich einen nullptr und keinen pointer auf die vertices), da nur die Buffergrösse festgelegt werden soll.

    Mit glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(VertexVN), vertices.data())"lade" ich dann in der Memberfunktion SetBuffer der Basisklasse die vertices in den Buffer.

    Es kann dann sein, wenn ich nach SetShape(position, radius) SetResolution aufrufe (in SetShape wird auch SetBuffer aufgerufen) , die vertices nicht mehr im Buffer sind und die Draw Anweisung "crasht".

    SetResolution war public, dann private jetzt protected, aber in einer neuen zusätzlichen Basisklasse für CircleShape und CircleSectorShape.

    Bin per google "funktion überladen in abgeleiteter klasse" auf eine sehr altes Thema "Basisklassenmethode in abgeleiteter Klasse überladen - Wie?" im C++-Forum gestossen. Da ich dachte, dass ich alle gemeinsamen Variablen und Funktionen in die neue Basisklasse schiebe. Aber die Funktionen sollen in den abgeleiteten Klassen auch überladen werden und das geht scheinbar nur im gleichen Scope (Sichtbarkeitsbereich) bzw. in der gleichen Klasse, sonst werden die Funktionen der Basisklasse überdeckt oder überschrieben.

    Sind eigentlich alle Variablen bzw. Objekte und Funktionen einer Klasse Membervariablen und Memberfunktionen, oder wird zwischen public, protected, private und aus Basisklassen übernommenen Variablen bzw. Objekte und Funktionen entsprechend unterschieden.

    Vielen Dank für alles 👍


Anmelden zum Antworten