Seltsam: Pointer mit X.sth() UND X->sthElse()



  • Hi,

    ich habe hier ein seltsames ... "Ding": Einen Pointer (einen "Smart Pointer", um genauer zu sein), der sowohl Methoden ueber X.abc als auch ueber X->def zur Verfuegung stellt.

    Weiss jemand, wie das moeglich sein soll? (Vorab: Ich programmiere gerade an einem Projekt, wo das funktioniert! Ich verstehe es nur nicht ... :))

    danke & Gruesse,

    Axel.

    p.s.: das ist ein COM-pointer, also der scheint auf ein Interface zu zeigen. Genaue Definition ist:

    typedef _com_ptr_t<com_IIID<IPlatform, 0x0>> IPlatformPtr
    

    p.p.s.: Falls jemand ein gutes Buch ueber COM kennt - gerne bescheid sagen ...



  • Hört sich nett an, Sinn und Zweck leutet mir auch nicht ein und vorallem nicht die Umsetzung der Speicherreservierung, bzw. Referenzierung. 😕 😮 😕



  • JA, in der Tat. Ich ueberlegte schon in Richtung statische Funktionen (.) vs. dynamische (->) ... aber das macht auch so irgendwie keinen Sinn ...



  • liessen sich diese operatoren ueberladen?



  • Hab mal was unter dem type library import gefunden wo es ein wenig beschrieben wird.

    Schlau hat es mich aber auch nicht gemacht.

    Siehe: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_predir_The_.23.import_Directive.asp

    codeman



  • Man kann den -> Operator überladen:

    struct A {
      void foo() { cout << "A::foo"; }
    };
    class B {
      A* a;
    public:
      // ctor/dtor bitte selbst dazudenken
      void foo() { cout << "B::foo"; }
      A* operator->() { return a; }
    };
    ...
    B b;
    b.foo(); // -> "B::foo"
    b->foo(); // -> "A::foo"
    

    Der Operator -> wird dabei rekursiv solange angewendet, bis ein Pointer herauskommt und damit ein tatsächlicher Memberzugriff stattfindet, d.h. X->Y bedeutet bei überladenem -> das gleiche wie (X.operator->())->Y. Falls dieser zweite -> immer noch überladen ist, setzt sich die Kette fort.



  • watt? welche? 🙂
    weiss nicht. Moment..... hm.
    ich schaute gerade durch die Klassendefinition in comip.h, und siehe da - ich fand etwas sehr, sehr, sehr seltsames.

    Interface* operator->() const 
        { 
            if (m_pInterface == NULL) {
                _com_issue_error(E_POINTER);
            }
    
            return m_pInterface; 
        }
    

    Darf man -> denn ueberhaupt ueberladen? Ich dachte naemlich, das ginge gar nicht ..... Wie nutzt man denn in diesem Fall einen Zeiger auf diese Klasse?!? 😕

    In diesem Fall allerdings wirds klar. Ueberladen von -> liefert den eigentlichen Interface-Pointer zurueck, auf dessen Funktionen ich dann zugreife. Mir etwas unverstaendlich, aber isso ... (was passiert, wenn ich -> ueberlade, und einen Zeiger auf eine solche Klasse mittels new() erzeuge, frage ich mich ... ?)



  • Axel++ schrieb:

    Darf man -> denn ueberhaupt ueberladen? Ich dachte naemlich, das ginge gar nicht ..... Wie nutzt man denn in diesem Fall einen Zeiger auf diese Klasse?!? 😕

    Der überladene Operator kommt natürlich nur zum Tragen, wenn er auf die Instanz selbst angewendet wird, nicht auf einen Zeiger.



  • Jop das ist es 😉 . Eine sehr verwirrende Sache für den der den Code später vielleicht mal lesen und weiterentwickel muß 🙄 , aber spart schon viele einzelne Objekte die man sonst vielleicht anlegen müsste. Geile Sache 😮 😋

    codeman



  • Bashar schrieb:

    Man kann den -> Operator überladen:

    struct A {
      void foo() { cout << "A::foo"; }
    };
    class B {
      A* a;
    public:
      // ctor/dtor bitte selbst dazudenken
      void foo() { cout << "B::foo"; }
      A* operator->() { return a; }
    };
    ...
    B b;
    b.foo(); // -> "B::foo"
    b->foo(); // -> "A::foo"
    

    ...

    OK, "ich-nix-raffen", Teil II. Warum funktioniert das? Ich meine, in B existiert ein Zeiger auf A, nirgendwo wird ein A-Objekt instantiiert, und trotzdem wird korrekt "A::foo" ausgegeben. Nicht mal mit Compiler-Warnung, und das vollkommen ohne die Klasse A zu instanziieren (ich habs mit struct UND Klasse eben getestet, es funktioniert). (Ausserdem ist die Methode nicht statisch, wobei das in C++ und Java vermutlich zwei verschiedenen Dinge sind) ... .

    Also, warum funktioniert gerade dieses Beispiel? (Ist vielleicht ne dumme Frage, aber es ist eine :))



  • Das ist halt C++. Das geht deshalb weil "this" von A hier nicht verwendest wird...

    Änderst Du A nach

    struct A { 
      void foo() { std::cout << "A::foo" << m_i; } 
      int m_i;
    };
    

    oder

    struct A { 
      virtual void foo() { std::cout << "A::foo"; } 
    };
    

    so geht es nicht...



  • Jochen Kalmbach schrieb:

    Das ist halt C++. ...

    Das hast du schoen gesagt 🙂

    Ausserdem danke fuer eure schnellen Antworten! Es ward Licht in meinem Schaedel ...



  • Jochen Kalmbach schrieb:

    Das ist halt C++. Das geht deshalb weil "this" von A hier nicht verwendest wird...

    Änderst Du A nach

    struct A { 
      void foo() { std::cout << "A::foo" << m_i; } 
      int m_i;
    };
    

    oder

    struct A { 
      virtual void foo() { std::cout << "A::foo"; } 
    };
    

    so geht es nicht...

    Sehe ich das richtig, daß es nicht gehen würde weil man mit:

    this->m_i
    

    oder

    bei einer Ableitung dann indirect this->foo
    

    nicht mehr überlagern könnte?



  • @Axel++:

    nirgendwo wird ein A-Objekt instantiiert

    Das sollte in dem "selbstgedachten" Konstruktor passieren.
    Der Code läuft "ausnahmsweise" auch so, und hat nix mit dem überladenen operator-> zu tun (s.u.)

    _com_ptr_t soll sich wie ein Zeiger (auf ein COM-Interface) verhalten, aber noch zusätzliche Aufgaben übernehmen (in deinem Fall die COM-Referenzzählung mittels AddRef und Release). Das ist die "netteste" Anwendung von überladenen Operatoren: einen neuen Typ zu schaffen, der sich wie ein eingebauter Typ verhält.

    Du kannst fast alle Operatoren überladen (was nicht heiußt das du es immer solltest). Was wirklich nicht geht ist z.B. operator .() (Memberzugriff) - mehr Infos unter http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/overl_9.asp

    ---------------------

    Das folgende läuft auch ohne Fehlermeldung, obwohl es eigentlich falsch ist:

    struct A { void foo() { cout << "A::foo" << endl; } };
    
    int main()
    {
      A * a;    // uninitialisiert
      a->foo();
    }
    

    Weder der Methodenaufruf noch die Methode A::foo greifen auf die Instanz zu, somit greift auch niemand auf den uninitialisierten Zeiger zu.



  • Man kann es natürlich schon überlagern... nur würde der "this"-Zeiger halt ins niergendwo zeigen und somit (in den meisten Fällen) eine Exception werfen...



  • Also bräuchte man einen Konstruktor, was das überlagern wieder sinnfrei machen würde, da nun "this" die Überlagerung wäre?



  • codeman schrieb:

    Also bräuchte man einen Konstruktor, was das überlagern wieder sinnfrei machen würde, da nun "this" die Überlagerung wäre?

    ????
    Einen Konstruktor brauchst Du nur um die Member-Variablen zu initialisieren (geht leider nicht inline wie in C# 😞 ). Das hat aber gar nichts mit dem überlagern zu tun.



  • wovon redet ihr grad??



  • Ich weiss auch nicht 😕


Anmelden zum Antworten