In genere, un sacco di codice non fa altro che ottenere/impostare i membri della classe. Per questo ho implementato una semplice classe contenitore per avere getter e setter associati a in un "campo". A prima vista questo sembra abbastanza ok e si traduce in codice molto meno. Questo è come la classe del contenitore si presenta come:È possibile implementare accessi Q_PROPERTY READ/WRITE senza utilizzare le funzioni membro?
Member.h
#include <functional>
template <class T>
class Member
{
public:
T data;
using Getter_t = std::function<T(void)>;
using Setter_t = std::function<void(T)>;
using Notify_t = std::function<void(void)>;
Setter_t m_setterFunc;
Getter_t m_getterFunc;
Notify_t m_notifyFunc;
Member()
{
this->m_getterFunc = [=] (void) -> T { return this->data; };
this->m_setterFunc = [=] (T data) -> void { this->data = data; };
this->m_notifyFunc = [] (void) -> void { };
}
auto get() -> T { return this->m_getterFunc(); }
auto set(T data) -> void { this->m_setterFunc(data); this->m_notifyFunc(); }
auto getter(Getter_t func) -> Member& { this->m_getterFunc = func; return *this; }
auto setter(Setter_t func) -> Member& { this->m_setterFunc = func; return *this; }
auto notify(Notify_t func) -> Member& { this->m_notifyFunc = func; return *this; }
~Member() { }
};
So che alcune cose non sono ancora perfetto, ma va bene per ora. Le righe successive mostrano come sono definite le istanze Member
e il modo semplice e conveniente per accedere ai dati sottostanti. Le funzioni get
, set
e notify
possono essere sostituite da lambda o puntatori di funzioni per sovrascrivere il comportamento personalizzato.
main.cpp
#include <iostream>
#include "Member.h"
class MyClass
{
public:
Member<int> foo;
Member<std::string> bar;
void barChanged() { std::cout << "bar changed\n"; }
};
auto main(int argc, const char * argv[]) -> int
{
MyClass instance;
instance.foo.notify([]() -> void { std::cout << "foo changed\n"; });
instance.bar.notify(std::bind(&MyClass::barChanged, instance));
instance.foo.set(10);
instance.bar.set("some string");
std::cout << instance.foo.get() << " " << instance.bar.get() << std::endl;
return 0;
}
Il problema ora è che la macro Q_PROPERTY
si aspetta nomi di funzione per i READ
e WRITE
di accesso e sono tornato dove ho iniziato: devo scrivere ottenere e impostare funzioni per ogni proprietà in modo esplicito. Esattamente quello che volevo evitare.
class MyOtherClass : public QObject
{
Q_OBJECT
Q_PROPERTY(bool flag READ getFlag WRITE setFlag NOTIFY flagChanged);
public:
Member<bool> m_flag;
auto getFlag() -> bool { return m_flag.get(); }
auto setFlag(bool flag) -> void { this->m_flag.set(flag); }
};
E 'possibile utilizzare direttamente i già esistenti m_flag.get
e m_flag.set
funzioni? Ho provato le cose ovvie ma sono state respinte dal moc o hanno causato troppi codici.
Modifica
Come indicato di seguito, la parola chiave MEMBER
permette di avere proprietà senza specificare get e set funzioni. Tuttavia, è possibile accedere ai membri privati solo con il loro nome (this->property("myPropertyName")
) e inoltre non è possibile ottenere più di "semplici" get e set.
Per renderlo più chiaro: La motivazione non è quello di evitare proprio la scrittura ottenere e funzioni di set, ma cercando di implementare un sistema di utente flessibile che
- da esegue di default get/set come previsto
- supporti personalizzati logico (ad esempio avanti recente valori impostato un altro esempio)
- possono essere utilizzati per i membri della classe C++ ed è compatibile con proprietà Qt
e il su il pezzo mancante è il ponte tra gli accessor Q_PROPERTY
READ
/WRITE
ei metodi get/set della classe Member
.
Grazie per qualsiasi aiuto!
Forse dovresti provare un po 'di magia con i macro? Riunisci una macro 'Q_PROPERTY' a un'altra che creerà 2 metodi + dichiara una proprietà. Non sono sicuro, ma potrebbe non essere compatibile con il compilatore MOC. –
In alternativa: consente di creare proprietà dinamiche in fase di runtime. –
@SaZ Cercherò di evitare le macro nel miglior modo possibile. Ma le proprietà dinamiche potrebbero essere un'opzione, ci proverò. Grazie per il suggerimento! – qCring