Properties

Schnelle objektorientierte, kompilierende Programmiersprache.
Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Properties

Beitrag von Glocke » Mi Apr 24, 2013 1:28 pm

Hi, ich hab' mir mal Gedanken gemacht, wie man Properties in C++ realisieren könnte. Über den Vorteil lässt sich streiten, dennoch würde mich mal eure Meinung zu meiner einfachen Implementierung interessieren :)

Code: Alles auswählen

template <typename Type, typename Parent>
class property {

    protected:
        Parent* parent;
        Type (Parent::*getter)();
        void (Parent::*setter)(Type);
        
        Type get() {
            return (this->parent->*getter)();
        }
        void set(Type value) {
            (this->parent->*setter)(value);
        }
    
    public:
        property(Parent* parent, Type (Parent::*getter)(), void (Parent::*setter)(Type))
            : parent(parent)
            , getter(getter)
            , setter(setter) {
        }
        
        property<Type, Parent>& operator=(Type value) {
            this->set(value);
        }
        property<Type, Parent>& operator+=(Type value) {
            Type current = this->get();
            current += value;
            this->set(current);
        }
        property<Type, Parent>& operator-=(Type value) {
            Type current = this->get();
            current -= value;
            this->set(current);
        }
        property<Type, Parent>& operator*=(Type value) {
            Type current = this->get();
            current *= value;
            this->set(current);
        }
        property<Type, Parent>& operator/=(Type value) {
            Type current = this->get();
            current /= value;
            this->set(current);
        }
        
        // @todo: Weitere Operatoren: + - * /  == != <= => < >
        
        operator Type() {
            return this->get();
        }
};
Ein Beispiel könnte so aussehen:

Code: Alles auswählen

class Example2 {
    protected:
        int _value;
        
        int getValue() {
            return this->_value;
        }
        void setValue(int value) {
            if (value < -10) { value = -10; }
            if (value > 100) { value = 100; }
            this->_value = value;
        }

    public:
        // Deklaration der Property
        property<int, Example2> value;

        Example2()
            // Wert initialisieren
            : _value(0)
            // Property initialisieren
            , value(this, &Example2::getValue, &Example2::setValue) {
        }
};

// ----------------------------------------------------------------------------

int main() {
    Example2 e;
    e.value = 5;
    e.value *= 2;
    int i = e.value;
    std::cout << i << "\n";
}
LG Glocke

/EDIT: Prinzipiell ließe sich auch Read-Only / Write-Only realisieren - dann aber imho nur zur Laufzeit.

jeanluc
Beiträge: 33
Registriert: Mo Apr 22, 2013 10:18 pm

Re: Properties

Beitrag von jeanluc » Mi Apr 24, 2013 4:00 pm

Schick schick, wobei ich persönlich versuche für solche Geschichten eine fertige Bibliothek zu finden.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Properties

Beitrag von Xin » Mi Apr 24, 2013 10:19 pm

Wie versprochen eine Rückmeldung - ich kann sowas nur nicht während der Arbeit ausprobieren - da soll ich ja für die arbeiten.
Ich habe jetzt keine Methodenzeiger verwendet, sondern einfach Funktionen, aber type::*get wäre ja auch möglich.

Warum ließ sich ro/rw nur zur Laufzeit realisieren?

Code: Alles auswählen


#include <stdio.h>

template< typename type, type (*get)( type in ) >
class readonly
{
  private:
    type operator =( type & rhs ) {}
  protected:
    type Data;
    
  public:
    explicit readonly( type data )
      : Data( data ) {}
      
    operator type () const
    { return get( Data ); }
};

template< typename type, type (*get)( type in ), type (*set)( type out )>
class readwrite : public readonly< type, get >
{
  public:
    readwrite( type data )
      : readonly< type, get >( data ) {}

    type operator =( type const & rhs )
    {
      return readonly< type, get >::Data = set( rhs );
    }
};

int int_get( int data )
{
  printf( "get int: %d\n", data );
  return data;
}

int int_set( int data )
{
  printf( "set int: %d\n", data );
  return data;
}

int main()
{
  readonly< int, int_get > ro( 1 );
  readwrite< int, int_get, int_set > rw( 4711 );
  
  int temp = ro;
  
//  ro = 4;   // geht nicht
  temp = rw;
  rw = 1234;
  
  printf( "----\n" );
  
  printf( "ro: %d, rw: %d", (int)ro, (int)rw );
};
Führt zu - erster Versuch mit der Zuweisung von ro = 4, dannach auskommentiert.

Code: Alles auswählen

apoc:glocke xin$ g++ property.cpp 
property.cpp: In function ‘int main()’:
property.cpp:51: error: no match for ‘operator=’ in ‘ro = 4’
property.cpp:7: note: candidates are: type readonly<type, get>::operator=(type&) [with type = int, type (* get)(type) = int_get]
property.cpp:5: note:                 readonly<int, int_get>& readonly<int, int_get>::operator=(const readonly<int, int_get>&)
apoc:glocke xin$ g++ property.cpp 
apoc:glocke xin$ ./a.out 
get int: 1
get int: 4711
set int: 1234
----
get int: 1234
get int: 1
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: Properties

Beitrag von Glocke » Do Apr 25, 2013 6:02 am

Xin hat geschrieben:Wie versprochen eine Rückmeldung - ich kann sowas nur nicht während der Arbeit ausprobieren - da soll ich ja für die arbeiten.
Sehr gut :D
Xin hat geschrieben:Ich habe jetzt keine Methodenzeiger verwendet, sondern einfach Funktionen, aber type::*get wäre ja auch möglich.
Naja gut, wenn ich aber getter/setter - die ich als Klassenmethoden geschrieben habe - für die Property verwenden will, brauche ich afaik zwingend Funktionszeiger. Oder irre ich mich da?
Xin hat geschrieben:Warum ließ sich ro/rw nur zur Laufzeit realisieren?
Weil ich nicht nachgedacht habe ^^ Klar geht das (wie du gezeigt hast xD)

LG Glocke

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Properties

Beitrag von Xin » Do Apr 25, 2013 7:49 am

Glocke hat geschrieben:
Xin hat geschrieben:Ich habe jetzt keine Methodenzeiger verwendet, sondern einfach Funktionen, aber type::*get wäre ja auch möglich.
Naja gut, wenn ich aber getter/setter - die ich als Klassenmethoden geschrieben habe - für die Property verwenden will, brauche ich afaik zwingend Funktionszeiger. Oder irre ich mich da?
Hier wird ja auch mit Funktionszeigern gearbeitet, aber die werden in das Template reinkompiliert. Du kannst ja statische Funktionen in die Klasse einbauen. Wenn Du Methoden verwenden möchtest, brauchst Du Methodenzeiger (type::*get, ...), die Du aber ebenfalls in das Template einbinden kannst.
Eigene Methoden oder Funktionszeiger brauchst Du nur, wenn Du die Methode/Funktion zur Laufzeit auswechseln möchtest - dann musst Du Dir merken, welche Du gerade benutzt.

Im ausgeschlafenen Zustand muss ich sagen, dass zumindest set nicht gut implementiert ist: Es sollte jedenfalls nicht nur den neuen Wert erhalten, sondern auch Zugriff auf den vorherigen Wert haben, um diesen zurückgegeben zu können, falls der neue Wert inakzeptabel ist. Also Methode oder zumindest int set( int old, int new ).
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

GilbertDur
Beiträge: 105
Registriert: Fr Mär 01, 2013 10:31 am

Re: Properties

Beitrag von GilbertDur » Do Apr 25, 2013 9:12 am

man könnte eventuell noch ein bisschen Ausnahmebehandlung einbauen :D

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Properties

Beitrag von Xin » Do Apr 25, 2013 9:15 am

GilbertDur hat geschrieben:man könnte eventuell noch ein bisschen Ausnahmebehandlung einbauen :D
Welche Ausnahme?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

GilbertDur
Beiträge: 105
Registriert: Fr Mär 01, 2013 10:31 am

Re: Properties

Beitrag von GilbertDur » Do Apr 25, 2013 11:08 am

Hmm, ich dachte man könnte in C++ ähnlich zu C# z.B. eine Nullpointer-Exception werfen und behandeln. Allerdings sagt mir ein bisschen Google Recherche folgendes: "Dereferencing a nullptr is undefined behavior . This is trying to use an exception to catch undefined behavior. Fundamentally, you cannot do that in C++." Interessant, das hatte ich schon wieder vergessen.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Properties

Beitrag von Xin » Do Apr 25, 2013 11:15 am

GilbertDur hat geschrieben:Hmm, ich dachte man könnte in C++ ähnlich zu C# z.B. eine Nullpointer-Exception werfen und behandeln. Allerdings sagt mir ein bisschen Google Recherche folgendes: "Dereferencing a nullptr is undefined behavior . This is trying to use an exception to catch undefined behavior. Fundamentally, you cannot do that in C++." Interessant, das hatte ich schon wieder vergessen.
Wo sollte es denn hier zu einem Null-Pointer-Zugriff kommen?

Um eine Exception zu werfen, müsste man ja erstmal einen Grund schaffen...?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: Properties

Beitrag von Glocke » Do Apr 25, 2013 11:41 am

Xin hat geschrieben:Wo sollte es denn hier zu einem Null-Pointer-Zugriff kommen?
Vielleicht meint er eine NULL als Funktionszeiger.. allerdings würde die Implementierung separater readonly, writeonly und readwrite Properties das Angeben von NULL als Funktionszeiger in der Initialisierung der Property sinnlos machen, d.h. Fehler auf Layer 8 ^^

Antworten