Per Referenz auf Initializer-List zugreifen



  • Hey Leute,

    habe ein Problem mit folgendem beispielhaftem Code:

    A(std::initializer_list<P> list)
    {
      for (const auto& elem : list)
      {
        std::cout << typeid(&elem).name() << std::endl;
      }
    }
    

    Hierbei sollen A und P Klassen sein und das obige ein Konstruktor der Klasse A, welches eine C++11 initializer list erwartet.

    Der obige Konstruktor soll nun die übergebene Liste durchgehen und jeweils den Typ der Elemente ausgeben.

    Das Problem ist nun folgendes:

    In der Liste befinden sich fast ausschließlich Objekte von Unterklassen von P und ich möchte gerade diese Typen ausgeben lassen und nicht immer den Typ P, was mit dem obigen Code aber leider nicht geht. Wisst ihr warum?

    Ein dynamic_cast hat mir hier auch nicht weitergeholfen.

    Sind z.B. C1 und C2 Unterklassen von P, dann konnte ich ein Objekt c1 der Klasse C1 in ein C2 Objekt casten ohne einen null-pointer zu bekommen, was mich etwas wundert.

    Hoffe jemand von euch kann mir hier weiterhelfen 🙂

    Gruß und schönen Abend an alle 🙂



  • MatheStein schrieb:

    Hey Leute,

    habe ein Problem mit folgendem beispielhaftem Code:

    A(std::initializer_list<P> list)
    {
      for (const auto& elem : list)
      {
        std::cout << typeid(&elem).name() << std::endl;
      }
    }
    

    Der Code ist schon an sich bescheuert. Denn der Typ ist einfach (immer) ein Zeiger auf P.

    MatheStein schrieb:

    Der obige Konstruktor soll nun die übergebene Liste durchgehen und jeweils den Typ der Elemente ausgeben.

    Aha, und wofür wenn ich bitten darf? Das, wovon ich denke dass du es willst, ließe sich mit einfachen Enumerationen lösen.

    MatheStein schrieb:

    Das Problem ist nun folgendes:

    In der Liste befinden sich fast ausschließlich Objekte von Unterklassen von P und ich möchte gerade diese Typen ausgeben lassen und nicht immer den Typ P, was mit dem obigen Code aber leider nicht geht. Wisst ihr warum?

    Wie soll das gehen? Was du bekommst ist eine initializer_list von Stackobjekten des Typs P, keine Basisklassenpointer o. ä....

    MatheStein schrieb:

    Sind z.B. C1 und C2 Unterklassen von P, dann konnte ich ein Objekt c1 der Klasse C1 in ein C2 Objekt casten ohne einen null-pointer zu bekommen, was mich etwas wundert.

    Zeig mal Code.



  • Das war jetzt ein total beispielhafter Code.

    Ich will einfach in dem Konstruktor alle Elemente der init-list durchgehen und je nachdem war für ein Objekt sich eigentlich dahinter verbirgt anders reagieren.

    am liebsten wäre mir in (Pseude-Code) so etwas wie:

    switch(Person* p)
    {
    case: type(p) == Mann
      /* ... */
    
    case: type(p) == Frau
      /* ... */
    
    case: type(p) == Kind
      /* ... */
    
    /* ... */
    }
    

    wobei p ein Zeiger auf ein Objekte welches ursprünglich den Typ "Mann", "Frau", "Kind", ... hatte
    (dass dies kein gültiger C++ Code ist, ist denke ich jedem klar, nur so verstehen die meisten sicher besser wonach hier gesucht ist)

    Gruß 🙂

    EDIT:

    http://en.cppreference.com/w/cpp/utility/initializer_list

    Hier sind ständig von Pointern die Rede mit denen das eigentlich klappen müsste, nur komischerweise bekomme ich als Rückgabetyp von beispielsweise "begin" keinen Pointer wie angegeben



  • Explizite Typunterscheidungen sind schlecht. Vor langer Zeit habe ich das ausführlicher begründet:

    Nexus (von <a href= schrieb:

    hier)">Einerseits sind Typunterscheidungen sehr fehleranfällig und müssen ständig mit der Klassenhierarchie konsistent bleiben. Wenn du Klassen berarbeitest, brauchst du an einem anderen Ort nochmals Code zu ändern. Bei dynamic_cast hast du zudem das Problem, dass die Reihenfolge der if - else -Statements richtig sein muss (abgeleitete müssen vor Basisklassen stehen). Bei typeid tritt das zwar nicht auf, dafür muss der Typ exakt stimmen, du kannst also mit Basisklassenabfragen keine abgeleiteten Klassen einschliessen. Ein weiteres Problem, das die Zentralisierung des Verhaltens mit sich bringt, ist die starke Abhängigkeit von Code. Bei der Typabfrage müssen nämlich alle Klassen vollständig bekannt sein. Besonders bei grösseren Projekten kann das die Kompilierzeit massiv beeinträchtigen, im Falle mehrerer Typabfragen in unterschiedlichen Modulen umso mehr.

    Das Wichtigste ist aber wohl, dass explizite Typunterscheidungen den Grundsatz der Polymorphie verletzen. Polymorphie (nicht nur dynamische) erlaubt es einem, Objekte mit unterschiedlichem Verhalten einheitlich anzusprechen, was eine starke Abstraktion ermöglicht. Mit manuellen Fallunterscheidungen verwirft man dieses Konzept und geht einen Schritt zurück – weg von objektorientierter Programmierung, in der ein Objekt selbst für sich schaut.

    Nimm virtuelle Funktionen.



  • Nexus schrieb:

    Nimm virtuelle Funktionen.

    Meinst du, dass er eine virtuelle Funktion implementieren soll die den Namen der Klasse zurückgibt?

    Hacker schrieb:

    Mathestein schrieb:

    Sind z.B. C1 und C2 Unterklassen von P, dann konnte ich ein Objekt c1 der Klasse C1 in ein C2 Objekt casten ohne einen null-pointer zu bekommen, was mich etwas wundert.

    Zeig mal Code.

    Marterstein schrieb:

    Das war jetzt ein total beispielhafter Code.

    Nein, ich meine zu

    Mathesain schrieb:

    konnte ich ein Objekt c1 der Klasse C1 in ein C2 Objekt casten ohne einen null-pointer zu bekommen

    Dazu wollte ich Code sehen 😃



  • Sone schrieb:

    Meinst du, dass er eine virtuelle Funktion implementieren soll die den Namen der Klasse zurückgibt?

    Was würde das bringen? Man hat nach wie vor eine explizite Fallunterscheidung, nur halt nach Strings.

    Nein, vielmehr soll er in der Basisklasse eine virtuelle Funktion deklarieren, welche in den abgeleiteten Klassen überschrieben wird und dort eine spezifische Aktion ausführt (nämlich das, was im case stehen würde).



  • Nexus schrieb:

    Nein, vielmehr soll er in der Basisklasse eine virtuelle Funktion deklarieren, welche in den abgeleiteten Klassen überschrieben wird und dort eine spezifische Aktion ausführt (nämlich das, was im case stehen würde).

    Ich dachte, er will einfach nur alle Objekte in einer Liste durchiterieren und ausgeben, was sie sind...

    In diesem Fall ist es natürlich lächerlich etwas anderes als virtuelle Funktionen zu benutzen.


Anmelden zum Antworten