2016-03-08 27 views
7

Nel mio anno di programmazione Qt, ho imparato molto su segnali e slot. Ma non basta ...Funzioni pubbliche rispetto alle aree pubbliche

http://doc.qt.io/qt-5/signalsandslots.html

slot possono essere utilizzati per la ricezione dei segnali, ma sono anche normali funzioni membro.

Quindi ... C'è qualche motivo per non dichiarare ogni singola funzione in una classe che eredita da QObject, come uno slot, se ha bisogno di essere uno o no?

Nel link qui sopra, danno un esempio:

una piccola classe QObject-based potrebbe leggere:

#include <QObject> 

class Counter : public QObject 
{ 
    Q_OBJECT 

public: 
    Counter() { m_value = 0; } 

    int value() const { return m_value; } 

public slots: 
    void setValue(int value); 

signals: 
    void valueChanged(int newValue); 

private: 
    int m_value; 
}; 

Perché definire la funzione value() come una funzione normale e non un fessura ? Ci sarebbero risultati negativi se lo facessero uno slot?

risposta

12

Indietro nei vecchi tempi, non avevi altra scelta che usare gli slot se vuoi connetterti ai segnali. Questo non è più il caso in Qt 5, dove le connessioni possono essere fatte a funzioni membro regolari o anche funzioni libere o lambda.

Dichiarare uno slot registra quella funzione nei metadati di quel particolare oggetto, rendendola prontamente disponibile a tutte le funzionalità di Qt che si basano sul meta oggetto. Oltre a questo, è una funzione membro normale come afferma la documentazione. Non c'è nulla di speciale nella stessa funzione di slot, la differenza è nella generazione di metadati per esso nel meta oggetto.

Ciò significa che dichiarare gli slot ha un costo, anche se piccolo, sia in termini di compilazione che di dimensioni eseguibili. Direi che è eccessivo avere tutte le tue funzioni pubbliche come slot. Sarebbe più efficiente usare solo gli slot quando effettivamente hai bisogno di slot, se non può funzionare con una funzione regolare, rendilo uno slot.

Inoltre, si noti che in quasi tutti i casi, i segnali vengono dichiarati con un tipo di ritorno void. Questo ha a che fare con il tipico caso d'uso dei segnali: spesso possono passare un parametro, ma raramente restituiscono qualcosa. Anche se è possibile restituire un valore attraverso un segnale collegato a uno slot, questo viene usato molto raramente. Quindi non ha molto senso dichiarare una funzione che restituisce qualcosa come uno slot a cui si intende connettersi, poiché il fatto stesso che restituisce un valore significa che molto probabilmente non verrà utilizzato nel tipico contesto di segnale/slot. Ecco perché il getter non è uno slot in questo esempio. Il setter come slot è ridondante in Qt 5 ed è probabilmente il prodotto di questo codice di esempio risalente a Qt 4.

Infine, separare gli slot dalle normali funzioni pubbliche è un buon modo per illustrare l'intento, o l'API "di quella classe se lo farai.Ad esempio, utilizzo principalmente gli slot per l'estensione di QML, quindi non è necessario contrassegnare esplicitamente tutte le funzioni come invocabili: a differenza dello scenario menzionato nel paragrafo precedente, tali slot spesso restituiscono elementi, ma non sono realmente utilizzati nelle connessioni. In questo modo ottengo una chiara panoramica del design dell'interfaccia fornita dalla classe.

-1

Per alcune funzioni, è necessario un valore di ritorno. Questo non funzionerà facilmente nelle slot. Nelle slot non è possibile utilizzare il valore di ritorno di una funzione o fornire ad esse un parametro di riferimento. Sì, puoi farlo, ma hai un problema di temporizzazione. Se si sta utilizzando uno slot o una normale funzione membro dipendente dall'architettura del software.

Inoltre, gli slot vengono eseguiti nel ciclo degli eventi. Dipende dal tuo codice se questo è intenzionale o meno.

+1

Questa risposta non ha il minimo significato, e non sembra nemmeno affrontare la domanda. – MrEricSir

+0

È possibile utilizzare i valori di ritorno negli slot? O addirittura ottenere il valore di un parametro di riferimento nel modo corretto? – SuperFliege

+1

@SuperFliege - lo slot è solo una funzione, funzionerebbe esattamente allo stesso modo di una funzione. Il multithreading e la durata dell'oggetto sono una questione completamente diversa e influiscono sulle funzioni regolari tanto quanto influiscono sugli slot. – dtech

2

In aggiunta alla risposta del ddriver, che è la risposta migliore/corretta (+1), vorrei anche sostenere che è fuorviante definire tutte le funzioni membro come aree pubbliche. Il modo in cui definisci le funzioni (privato/pubblico/posto connettore ecc.) Ha un effetto sull'utilizzo percepito della classe.

Ciò che intendo è .... si potrebbe sostenere che tutte le funzioni dovrebbero essere solo pubbliche (o pubbliche) e quindi questo copre tutti i casi. Tuttavia questo potrebbe essere fonte di confusione per un futuro utente della tua classe. Considerare che int value() è uno slot pubblico (non è il miglior esempio) qualcuno potrebbe provare a usarlo come uno, ma la funzione stessa ha un valore di ritorno che non ha realmente senso per uno slot. Ha senso per una funzione membro normale in cui (come una normale chiamata di funzione) è possibile accedere al valore di ritorno.

Una regola da seguire è quella di mantenere sempre le proprie funzioni e variabili locali e private il più possibile (per impostazione predefinita) e aprirle solo per un altro uso (publicità, slot, globale, ecc ...) quando ne hai davvero bisogno. Ciò mantiene la tua interfaccia di classe molto più facile da capire ed evita la confusione per gli utenti successivi.

Sono sicuro che c'è un nome per questa regola del pollice in modo da poter cercare su qualche sito tecnica di codifica, ma non riesco a ricordarlo :(

modificare

Un altro piccolo esempio è il completamento automatico ... se tutte le tue funzioni sono slot, quando stai facendo il tuo connect(this, myClass::mySignal, &someOtherClass, SomeOtherClass::<auto complete options>); il tuo elenco di opzioni di completamento automatico potrebbe essere lungo e poco chiaro cosa è cosa.Se hai solo alcuni membri specifici che sono slot quindi è più facile sapere quale scegliere:

+1

Il termine che stavi cercando è l'incapsulamento. – thuga

+0

@thuga - Sì, l'incapsulamento è sicuramente il soggetto ... ma sono sicuro che ci sia un "nome per la regola" per tenere tutto in minima parte ... forse sono solo le "regole dell'incapsulamento"?: o grazie:) –

+0

L'unica cosa che aggiungerei a questa risposta è che gli slot pubblici sono Q_INVOKABLE e potresti non voler che tutti i tuoi metodi pubblici siano accessibili da un contesto QML. – MrEricSir

2

In riferimento all'enca la psulazione dalla risposta di code_fodder, si dovrebbe notare che non esiste realmente uno spazio privato.

Ad esempio:

class MyClass : public QObject 
{ 
    Q_OBJECT 
public: 
    MyClass() 
     :QObject(NULL) {} 

private slots: 
    void Hello() { qDebug("Hello World\n"); } 
}; 

#include "main.moc" 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    MyClass* cls = new MyClass; 
    QMetaObject::invokeMethod(cls, "Hello"); 

    return a.exec(); 
} 

Come possiamo vedere qui, chiamando la funzione Hello è successo al di fuori della classe.

+0

Funziona anche per le connessioni? A proposito, la responsabilità per la possibilità di invocare funzioni private è interamente su Qt, non c'è controllo di accesso. Le slot private sono molto reali, anche se non rispettate dal meta system :) – dtech

+0

Sì, se ci si connette tramite il vecchio metodo di connessione (pre Qt 5), utilizzando le macro SIGNAL, SLOT. Ad esempio con un QTimer * connect (pTimer, SIGNAL (timeout()), cls, SLOT (Hello())); * – TheDarkKnight

+1

@TheDarkKnight è un'osservazione davvero interessante (+1 per la condivisione). Io uso sempre gli slot privati ​​quando configuro la connessione interna all'interno della stessa classe e pubblico altrimenti ... ma non ho mai pensato di verificare (o di notare) che Qt non inibisce la visibilità dello slot privato! - ancora, questo non cambierà il modo in cui li definisco perché anche se Qt è clemente (o semplicemente sbagliato qui) non mi piace essere:) –

0

Un altro caso di utilizzo in cui non si desidera che tutti i metodi siano slot quando si espongono oggetti in JavaScript tramite Qt's WebKit Bridge: tutti gli slot pubblici sono invocabili da JavaScript.

Quindi, se si desidera un metodo pubblico non invocabile da JavaScript, non è possibile dichiararlo come uno slot.

+0

Il motivo principale della mia domanda era perché devo esporre oggetti a JavaScript - e le persone che usano quel particolare aspetto della mia applicazione sono molto felici di chiedere che praticamente ogni funzione possa essere uno slot. Sto cercando di limitare questo ... ma avevo bisogno di un motivo per cui. Per le funzioni che restituiscono un valore, le funzioni possono diventare richiamabili da JavaScript rendendole 'Q_PROPERTY'. – Thalia