Pointer-To-Pointer



  • ich versteh nicht ganz wo das problem liegt. der compiler _könnte_ in diesem speziellen fall erkenne, dass es sich sicher um ein B handelt (und daher evtl. spezielle optimierungen machen, wie z.b. virtuelle funktionsaufrufe auflösen). das bedeutet aber nicht, dass er das immer kann. und warum sollte man ein konstrukt erlauben, nur weil es manchmal möglich ist, falls der compiler schlau genug ist. außerdem zwingt deinen compiler niemand dazu es nicht einfach zu erlauben, wäre dann halt kein standard c++ mehr.

    und das zweite (mit den doppelpointern) hat mit dem ersten doch nix zu tun!?



  • ich auch nicht......:-)

    Aber ich hoffe das CStoll seinen Beitrag etwas erläutert. Er scheint verstanden zu haben, um was es geht.



  • SRY: ich sollte mal etwas genauer lesen...

    also die frage war warum das nicht geht:

    B* b = new B;
    A** = &b;
    

    ganz einfach, weil das auch nicht geht:

    float* blub = new float;
    int** pi = &blub;
    

    wenn du einen pointer auf eine abgeleitete klasse in einen pointer auf eine basisklasse umcastest, kann es sein, dass der pointer dabei verändert werden muss (damit er auch wirklich auf das in der abgeleiteten klasse enthaltene objekt der basisklasse zeigt).

    B* b = new B;
    A** a = &b;
    

    wäre das möglich, würde in so einem fall *a auf das falsche objekt zeigen.



  • dot schrieb:

    SRY: ich sollte mal etwas genauer lesen...

    also die frage war warum das nicht geht:

    B* b = new B;
    A** = &b;
    

    ganz einfach, weil das auch nicht geht:

    float* blub = new float;
    int** pi = &blub;
    

    ...

    😮 😕
    Also Deine Erklärungsversuche in allen Ehren, aber die hilft hier nicht weiter.
    DAS

    float* blub = new float;
    int** pi = &blub;
    

    geht nicht, weil auch

    int* blub = new float;
    

    nicht geht => weil int und float keine polymorphen Typen sind.

    Gruß,

    Simon2.



  • jo, A* und B* sind auch keine polymorphen typen!?



  • ok, jetzt reden wir über dasselbe. Wie muss der pointer "verändert" werden, damit er auf das richtige Objekt zeigt ? (Pointer enthalten ja eigentlich nur eine Speicheradresse und für den Compiler haben sie noch einen "Typ").

    Wohlgemerkt, das B ja ein A ist !



  • jo, pointer enthalten eine speicheradresse. ein pointer auf ein B zeigt auf den anfang des B objektes. da B von A abgeleitet ist, enthält ein B objekt auch ein A (ein A objekt ist ja ein teil von einem B objekt). deshalb kann man einen zeiger auf ein B auch in einen zeiger auf ein A umwandeln. der zeiger wird einfach so verändert, dass er auf das A in dem B zeigt. üblicherweise steht das A einfach am anfang, dann wäre keine veränderung notwendig, aber das ist implementation defined (es ist also im standard nicht definiert, dass beim upcast der zeiger gleich bleibt). spätestens wenn mehrfachvererbung und virtuelle basisklassen im spiel sind führt kein weg drum herum.



  • Ok, vielleicht stelle ich mich mit dem Verstehen etwas blöde an, aber nochmal zurück zum Beispiel:

    class A {};
    class B: public A {};

    B* pB = new B;
    A* pA = new A;
    A* pAB = pB;

    Geht:
    A** ppA1 = &pA;
    logisch, da pA ein pointer vom Typ A* (auf ein A ist) und man mit einem A** darauf zeigen kann. Typprüfung nachvollziehbar

    A** ppA1 = &pAB;
    logisch, da pAB ein pointer vom Typ A* (auf ein B ist) und man mit einem A** darauf zeigen kann. Typprüfung nachvollziehbar.

    Geht nicht:
    A** ppA2 = &pB;
    weil pB ein pointer vom Typ B* (auf ein B ist) und man mit einem A** nicht darauf zeigen kann, weil:
    man mit einem pointer vom Typ B* nur auf ein B zeigen kann, nicht aber auf ein A (da das die Elternklasse ist). Man kann einem pointer vom Typ B* nicht einen pointer vom Typ A* zuweisen (außer mit dynamic_cast oder static_cast).

    Ist das so richtig verstanden ?



  • jo, ich denk schon



  • fast richtig verstanden wuerd ich sagen. Du kannst Zeiger nur auf den zugehoerigen Typen oder einen davon abgeleiteten Typen zeigen lassen. pA sollte also auf ein A oder einen von A abgeleiteten Typen zeigen (wie du richtig erkannt hast). ABER:
    ppA ist ein Zeiger auf A*. A* wiederum ist ein Zeiger und kein Nutzerdefinierter Typ, und daher kann man von A* auch nichts baleiten. ergo kann ppA einzig und allein auf A* Variablen zeigen. Die Typen A* und B* haben sogesehen rein garnichts miteinander gemeinsam.



  • Die Typen A* und B* haben sogesehen rein garnichts miteinander gemeinsam.

    jo, das war es auch, was mein beispiel mit dem int und dem float aussagen sollte. das beispiel war nur von mir leider "etwas ungut" (saublöd) gewählt^^ sry dafür



  • Hallo Jungs, speziell Pumuckl,

    Endlich, ok das ist eine wirklich gute und verständliche Begründung. Jetzt ist alles klar ! Danke !

    Das mit Objektgröße/Polymorphie hat mich so wie oben gepostet etwas irritiert.

    PS. bleibt immer noch die Frage, warum man C++ nicht so definiert hat, dass es aus dem Zusammenhang A<->B auch den Zusammenhang A*<->B* erkennen kann....aber das wäre wohl ein anderer Post



  • PhilippMaurer schrieb:

    Was für ein Schwachsinn !!! Natürlich kann ich einem pointer vom Typ B* einem pointer vom Typ A* zuweisen, mach ich oben ja sogar ! Immer noch ein Rätzel...

    meinst du einem pointer vom typ B* einen poiner vom typ A* zuweisen oder umgekehrt?
    falls ersteres:
    nein, nicht ohne cast

    PhilippMaurer schrieb:

    bleibt immer noch die Frage, warum man C++ nicht so definiert hat, dass es aus dem Zusammenhang A<->B auch den Zusammenhang A*<->B* erkennen kann....aber das wäre wohl ein anderer Post

    was sollte das:

    A** ppA = &pB;
    

    deiner meinung nach tun?



  • Einen Pointer auf einen B Pointer der auf ein B zeigt, aber vom Typ A**. Da A die Elternklasse von B ist, wären folgende "Zeigerketten" für mich logisch einwandfrei:

    A** -> A* -> A (geht in C++)
    A** -> A* -> B (geht in C++)

    A** -> B* -> B (geht nicht in C++)



  • denk mal drüber nach was diese anweisung genau bedeutet:

    A** ppA = &pB;
    

    einem zeiger auf ein A* wird die adresse eines B* zugewiesen. wie soll das funktionieren? ein B* zeigt ja nicht auf ein objekt vom typ A!?
    ein B* kann lediglich in ein A* umgewandelt werden. das bedeutet nicht, dass ein B* ein A* ist. nachdem ein B* kein A* ist, wie soll also einem A** die adresse eines B* zugewiesen werde können!?

    das ist keine frage der definition von C++, sondern es ist einfach nicht möglich/sinnvoll.

    denk dir einfach folgendes:
    nehmen wir an deine B objekte sehen im speicher so aus

    ___________
    |         |
    |    B    |
    | _______ |
    | |     | |
    | |  A  | |
    | |_____| |
    |_________|
    

    ein B* würde auf den beginn des B objektes zeigen. wandelst du den zeiger in einen A* um, dann zeigt das ergebnis auf das A in dem B. der wert des zeigers ist ein anderer. wenn du jetzt einem A** die adresse eines B* zuweisen würdest, dann würde der A** auf einen wert zeigen der nicht auf das A, sondern auf das B zeigt.


  • Mod

    PhilippMaurer schrieb:

    Einen Pointer auf einen B Pointer der auf ein B zeigt, aber vom Typ A**. Da A die Elternklasse von B ist, wären folgende "Zeigerketten" für mich logisch einwandfrei:

    A** -> A* -> A (geht in C++)
    A** -> A* -> B (geht in C++)

    A** -> B* -> B (geht nicht in C++)

    Hier liegt ein Denkfehler schon beim einfachen Zeiger vor.
    Ein B* zeigt immer nur auf ein B und ein A* immer nur auf ein A aber niemals auf ein B. Da A die Basisklasse von B ist, kann ein A* auf ein A-Objekt zeigen, dass das Basisklassensubobjekt eines B-Objektes ist - aber auch dann zeigt unser A* nur auf das A-Subobjekt.
    Wenn die Adresse eines B bekannt ist, so lässt sich damit die Adresse das A-Subobjektes in diesem B ermitteln - und C++ ist freundlich genug, das Ganze als implizite Konvertierung zuzulassen - diese Tatsache sagt aber nichts über die Pointerobjekte selbst aus. Wenn ein A** auf ein B* zeigen könnte, setzte das voraus, dass ein B*-Objekt identisch mit einem A*-Objekt ist - aber der innere Aufbau von Pointern ist (nahezu) völlig unbestimmt. Ganz nebenbei muss die Adresse eines Basisklassensubobjektes nicht mit der das vollständigen Objektes übereinstimmen - bei Mehrfachvererbung ist das offensichtlich, aber auch bei Einfachvererbung gibt es diesbezüglich keine Beschränkungen.


Anmelden zum Antworten