Announcement

Collapse
No announcement yet.

Event handling in reinem C++

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Event handling in reinem C++

    Hallo,
    <br>
    <br>
    Ich habe ein grosses Problem:
    <br>
    Ich muss plattform- und compilerunabhängig eine Implementation von event handlern und properties
    schreiben.
    Ich würde die event handler gerne als callbacks implementieren. Bei Zeigern auf C++-Memberfunktionen geht das allerdings nicht Klassenunabhängig und ohne beim Aufruf die Instanz der Klasse anzugeben, und wegen dem versteckten this-pointer schon gar nicht für Member- und Nichtmemberfunktionen gleichzeitig (letzteres ist nicht unbedingt notwendig).
    Borland löst das Problem mit dem Schlüsselwort __closure, aber das untertützen leider nur die Borland-Compiler.
    <br>
    Properties liessen sich dann mittels templates als Klasse herstellen (den Typ dann per template angeben), wenn man den Konstruktor mit solchen event-handler-pointern für die Schreib- und Lesefunktionen füttern könnte.
    Für das Lesen und Schreiben könnte man dann alle möglichen Operatoren überladen, aber ich weiss leider nicht wie das genau geht (was welche Operatorfunktion zurückliefern muss etc.).
    __property (Borland) oder __declspec(property) (Microsoft) kann ich aus den genannten Gründen leider nicht verwende.
    <br>
    <br>
    Ich bin für jeden Hinweis sehr dankbar.
    <br>
    Peter

  • #2
    Hi Peter,<br>
    vielleicht ist die libsigc++ (libsigc.sourceforge.net) was für dich?
    <br>Ciao, Uli

    Comment


    • #3
      Hi, ich bin's nochmal.<br>
      Bzgl. Properties: Ich habe da auch mal ein bisschen mit
      Templates rumgespielt. Erreichen wollte ich, dass man das
      Ganze so ähnlich:
      <pre>
      property<int, FLeft, SetLeft> Left;
      </pre>
      verwenden kann. (Alle Beispiele in Delphi/BCB-Notation, also
      FLeft ist eine Membervariable und SetLeft eine Methode.)
      property wäre also irgendwas in der Art
      <pre>
      template<typename T, typename ReadAccessT, typename WriteAccessT>
      class property {...};
      </pre>
      Bei Lesezugriffen auf die Property müsste so was:
      <pre>
      // Template-Spezialisierung für ReadAccessT = T (vermutlich eher ReadAccessT = T& ?),
      // also Zugriff auf Membervariable:
      template<typename T, typename T, ...>
      property:perator T()
      {
      return FReferenzAufVariable;
      };
      </pre>
      zum Einsatz kommen, bei Schreibzugriffen
      <pre>
      template<typename T, typename T, ...>
      property:perator=(const T& Value);
      {
      FReferenzAufVariable = Value;
      };
      </pre>
      Das hätte aber den Nachteil, dass Properties Speicher in der enthaltenden
      Instanz belegen, was ich natürlich gerne vermieden hätte.
      <p>Leider habe ich die Lust verloren, bevor was Vernünftiges rausgekommen ist.
      Wenn du etwas in der Richtung aus die Beine stellst, kannst du es ja hier bekanntgeben --
      ich wäre jedenfalls neugierig darauf. :-)
      <p>Was mir gerade noch einfällt: Hast du schon mal bei Boost vorbeigeschaut.
      Da gibt's lauter tolle und verrückte C++-Tricksereien -- vielleicht auch
      Properties?
      <p>Ciao, Uli

      Comment


      • #4
        <p>Hi Ulrich,<br>
        Vielen Dank, deine Hinweise haben mich echt weitergebracht.
        </p>
        <p>
        Dein Tipp mit der libsigc++ ist echt interessant, vielleicht kann ich auf deren Basis was machen (als Hobbyprogrammierer dauert sowas bei mir immer etwas).</p>
        <p>
        Deine Lösung für properties scheint im Grunde auch genau das zu sein, was ich suche.<br>
        Mir ist aber noch nicht ganz klar, wie man die Members der Klasse property deklarieren muss.<br>
        Und ich bin mir auch nicht sicher ob man dann die Getter- und Setterfunktionen von Variablenreferenzen unterscheiden kann (in den Operatorüberladungen).
        </p>
        <p>
        Aber Du hast mich auf eine Idee gebracht:<br>
        Man könnt doch einfach nur <br>
        <pre>
        property<int>;
        </pre>
        <br>
        schreiben und dann im Konstruktor Zeiger auf die Variablen/Funktionen übergeben.<br>
        Damit müsste man nur zwei Zeiger speichern und die properties würden nicht den Speicher der enthaltenden Instanz belegen (glaube ich jedenfalls).
        </p>
        <p>
        Nochmal Danke<br>
        Peter
        </p&gt

        Comment


        • #5
          Hi Peter,<br>
          <i>Damit müsste man nur zwei Zeiger speichern und die properties würden nicht den Speicher der enthaltenden Instanz belegen (glaube ich jedenfalls). </i><br>
          Die Zeiger würden leider trotzdem in der Instanz Platz belegen.
          Und ich fürchte, dass die Properties selbst dann, wenn man diese Zeiger einsparen könnte, Speicherplatz bräuchten.
          Wenn nämlich aus einem Statement wie test.Left = 7 ein Aufruf a la test.SetLeft(7) werden soll, muss man das ja wohl mittels eines operator= erledigen. Der wiederum will eine Variable als linke Seite haben. Und Variablen belegen leider Speicher -- IIRC selbst "leere" Klassen ohne Membervariablen. (Ich glaube, um eindeutige Adressen == Identitäten für Objekte zu gewährleisten).
          <p>Aber vielleicht kommt ja einem von uns beim Experimentieren noch
          eine Erleuchtung. :-)
          <p>Ciao, Uli

          Comment


          • #6
            <p>Hi Uli,<br>
            Wenn das so ist, gibt es wohl keine bessere Lösung.<br>
            Man kann ja eigentlich nur eine Klasse nehmen, weil Makros keinerlei Möglichkeiten für Operatoren bieten.</p>
            <p>
            Dummerweise möchte ich noch RTTI Routinen schreiben, z.B. damit man die Eigenschaftswerte bequem in eine XML-Datei auslagern kann, und solche Spielchen.
            <br>
            Damit würde der Speicherplatz nochmal anwachsen, der von der property-Klasse in Anspruch genommen wird. Ein oder zwei Pointer fallen da auch nicht mehr so stark ins Gewicht. Aber die zusätzlichen Funktionen...<br>
            Die statisch zu machen bringt wohl auch nicht so viel (oder auch gar nichts?). Ich glaube das Problem ist einfach nur mit ein bisschen Speicherverschwendung zu lösen, (Borland macht es wohl ähnlich, nur sieht man das nicht :-)
            </p>
            <p>
            Ich hab es lange versucht, aber Getter und Setter bei der Deklaration in die spitzen Klammern zu setzen, so wie Du das vorgeschlagen hast, will einfach nicht klappen. Mein compiler beschwert sich über nicht konstante Ausdücke. Mein Ansatz mu&szlig; das alles wenig elegant im Konstruktor als Argument übernehmen (aber wahrscheinlich kann man eben sonst nich zwischen Variable und Funktion unterscheiden).
            </p>
            <p>
            Ciao, Peter.
            </p&gt

            Comment


            • #7
              Hi Peter,<br>
              mir ist auch nichts rechtes mehr eingefallen. In meinem C++-Code bleibt's wohl auch in Zukunft bei inline-Get- und Set-Methoden. Ist vielleicht ästhetisch nicht ganz so befriedigend, aber man kann halt nicht alles haben. :-)
              <p>Was die Properties bei Borland betrifft: Die Borländer haben den Vorteil, dass sie den Compiler verbiegen können. Dann ist es kein Problem, Properties ohne Overhead zu implementieren,
              <p>Ciao, Uli

              Comment


              • #8
                <p>
                Hi Uli,<br>
                Die Borländer können das gar nicht ganz ohne Overhead realisieren, denn es gibt in jedem Objekt eine Auflistung aller properties (auf die greift z.B der Objektinspektor zurück). Die Speichern sogar von allen __published-Methoden Name und Adresse (da gibt es auch irgendwo eine Möglichkeit, drauf zuzugreifen), damit sie in der DFM-Resource
                <pre>
                OnClick = Button1Click;
                </pre>
                auflösen können.<br>
                Damit wird auch irgendwie das ganze Streaming-System realisiert.
                </p>
                <p>
                Die speichern für ihre properties auch noch den Instanz-Namen, da sind unsere kleinen Klassen wohl noch fast als sparsam zu bezeichnen.
                </p>
                <p>
                Aber nochmal Danke, Haupsache das ganze funktioniert! :-)
                Ciao, Peter
                </p&gt

                Comment


                • #9
                  Der Overhead liegt aber nur am "published". Nicht-published-Properties sind AFAIK reine Compilezeitgeschichten, die 1:1 in die entsprechenden Variablen-/Methoden-Zugriffe umgesetzt werden.
                  Du willst wohl das Streaming auch mit haben?
                  <p>Ciao, Uli

                  Comment


                  • #10
                    <p>Hi Uli,<br>
                    </p>
                    <p>
                    Streaming fände ich echt interessant, nur hat man dann leider den ganzen Overhead dabei (das lässt sich ja leider nicht vermeiden).</p>
                    <p>
                    Es ist schon schön, wenn man seine Objekte aus Dateien laden kann, besonders für die Internatioanlisierung.</p>
                    <p>
                    Aber ganz so bequem wie bei Borland geht das wohl nicht, weil man den Properties im Konstruktor ihren Namen und den this-Zeiger der enthaltenden Klasse verraten muss (der typeid Operator leistet da auch nicht viel oder gar nichts).
                    </p>
                    <p>
                    Man muss dann vermutlich alle Klassen, die das unterstützen sollen von einer gemeinsamen Basisklasse ableiten (ähnlich TObject), die ein Array aus Zeigern auf die Properties speichert.<br>
                    Per RTTI könnte man vermutlich die Vererbung prüfen und auch nichtstreambare Klassen ohne oder mit wenig overhead erstellen.</p>
                    <p>
                    Dann müsste ein Parser (z.B. für XML) die Lese- und Schreibarbeit erledigen, und das ist natürlich auch nicht gerade resourcenschonend.
                    </p>
                    <p>
                    Ich glaube, dass Borland mit Compilermodifikationen und Apple (mit MacOS X/Cocoa lesen und schreiben die ja ganze Objekte zur Laufzeit) mit der eigenen Sprache da deutlich im Vorteil sind.<br>
                    Aber man kann ja mal ein wenig Speicher verschwenden, Intel & Co werden's uns danken. :-)
                    </p>
                    <p>
                    Ciao, Peter
                    </p&gt

                    Comment


                    • #11
                      <p>Hi,<br>
                      Zum Streaming: OnClick = Button1Click; lässt sich vermutlich nicht direkt auflösen.</p>
                      <p>
                      Was Borland über den Compiler macht (in __published), das lässt C++ in reiner Form nicht zu</p>
                      <p>
                      Allerdings wäres es wahrscheinlich möglich (zumindest unter Windows) mittels GetProcAddress sich Funktionsadressen zu beschaffen.<br>
                      Weil aber leider die Namensergänzung nicht standardisiert ist, müsste man wohl für jeden Compiler anderen Code verwenden.</p>
                      <p>Ciao, Peter</p&gt

                      Comment

                      Working...
                      X