2010-10-05 12 views
5

Capisco che un vantaggio di avere funzioni membro statiche non è dover inizializzare una classe per usarle. Mi sembra che un altro vantaggio potrebbe non avere accesso diretto alle cose non statiche della classe.Utilizzo della parola chiave "statica" per limitare l'accesso nelle funzioni membro C++

Ad esempio, una pratica comune è se si sa che una funzione avrà argomenti che non sono di essere cambiato, semplicemente marcare questi costante. ad esempio

bool My_Class::do_stuff(const int not_to_be_changed_1, 
         std::vector<int> const * const not_to_be_changed_2) 
{ 
    //I can't change my int var, my vector pointer, or the ints inside it. 
} 

Quindi è valido utilizzare le funzioni membro statiche per limitare l'accesso. Ad esempio, supponiamo di avere una funzione

void My_Class::print_error(const unsigned int error_no) { 
    switch (error_no) { 
    case 1: 
     std::cout << "Bad read on..." << std::endl; 
     break; 
    //... 
    default: 
     break; 
    } 
} 

Beh, qui non stiamo andando ad essere l'accesso a tutte le variabili membro della classe. Quindi, se ho cambiato la funzione di:

static void My_Class::print_error(const unsigned int error_no) { 
    switch (error_no) { 
    case 1: 
     std::cout << "Bad read on..." << std::endl; 
     break; 
    //... 
    default: 
     break; 
    } 
} 

mi piacerebbe ora ottengo un errore, se ho inavvertitamente provato ad accedere a uno dei miei private var, ecc (a meno che non mi passa me stesso un'istanza della mia classe, che avrebbe essere propositivo^_ ^!)

si tratta di una tecnica valida, simile a fare in modo proattivo args che non devono essere modificate le costanti?

Quali svantaggi potrebbero avere in termini di efficienza o utilizzo?

Il motivo principale per cui mi chiedo è che la maggior parte dei tutorial "statici" che ho letto non ha menzionato l'utilizzo in questo modo, quindi mi chiedevo se ci fosse un buon motivo per non farlo, considerando che sembra un utile strumento.


Edit 1: Una giustificazione ulteriore logica di questo uso:

Ho una funzione print_error come sopra. Potrei usare uno spazio dei nomi:

namespace MY_SPACE { 
    static void print_error(...) { 
     ... 
    } 

    class My_Class { 
     .... 
     void a(void) 
    } 
} 

ma questo è un dolore, perché ora ho di allungare tutti i miei dichiarazioni var, cioè

MY_SPACE::My_Class class_1; 

tutto per rimuovere una funzione della mia classe, che in sostanza è un membro della mia classe.

Naturalmente c'è più livelli di controllo di accesso per le funzioni:

//can't change pointer to list directly 
void My_Class::print_error(std::vector<int> const * error_code_list) {...} 

//can't change pointer to list or list members directly 
void My_Class::print_error(std::vector<int> const * const error_code_list) {...} 

//can't change pointer to list or list members directly, access 
//non-const member vars/functions 
void My_Class::print_error(std::vector<int> const * const error_code_list) const {...} 

//can't change pointer to list or list members directly, access 
//non-static member vars/functions 
static void My_Class::print_error(std::vector<int> const * const error_code_list) {...} 

//can't change pointer to list or list members directly, access 
//member vars/functions that are not BOTH static and const 
static void My_Class::print_error(std::vector<int> const * const error_code_list) const {...} 

sicuro che questo è un po 'atipico, ma per diminuire gradi in modo stanno utilizzando le funzioni e le variabili const const. Ho visto molti esempi in cui le persone avrebbero potuto usare una funzione const, ma non l'hanno fatto. Eppure alcune persone pensano che sia una buona idea. Conosco molti programmatori C++ che non capiscono le implicazioni di una funzione const o di una statica. Allo stesso modo molto capirebbe entrambi.

Quindi, perché alcune persone sono così categoricamente contrarie all'uso di questo come un meccanismo di controllo dell'accesso se la lingua/specifiche lo prevede di essere utilizzato come tale, proprio come fa con le funzioni const, ecc.?

+1

Sembra strano avere una funzione come membro di una classe se hai intenzione di negare i diritti di accesso ai membri. – JoshD

+2

Un modo migliore per limitare l'accesso sarebbe semplicemente utilizzare una funzione non membro. Non capisco davvero cosa stai cercando di proteggere contro, però. –

+1

Supponiamo che tu abbia una funzione membro che NON SA necessario per accedere alle variabili/funzioni membro al momento, ma è correlata al lavoro/funzione della classe. Concettualmente la sua inclusione nella classe ha senso, ma vuoi assicurarti che non ci sia accesso ai membri della classe. Quindi potresti renderlo una funzione statica, proprio come faresti con una variabile che vuoi impedire l'accesso a una variabile 'const'. Certo, potresti semplicemente non toccare la variabile/membri, e quindi non usare 'const' /' static', ma molti scelgono di sbagliare sul lato della cautela, almeno nel loro uso di 'const'. –

risposta

1

Le funzioni membro statico devono essere utilizzate quando sono rilevante per la classe ma non funziona su un'istanza della classe.

Gli esempi includono una classe di metodi di utilità, che sono tutti statici perché non è mai necessaria un'istanza effettiva della classe di utilità stessa.

Un altro esempio è una classe che utilizza le funzioni di supporto statico e tali funzioni sono abbastanza utili per altre funzioni esterne alla classe.

+0

Quindi, in base alla tua risposta, sembra il caso d'uso di esempio che ho originariamente affermato (una funzione di stampante di errore helper) sarebbe un candidato valido per 'static' nella tua mente. –

+0

@ Jason: Sì. Certo, credo che praticamente * tutte * le funzioni dovrebbero essere membri della classe (statici o meno). Le funzioni bare rompono l'orientazione agli oggetti (anche se mi rendo conto che le funzioni di template non membro sono utili come funzioni helper "glue"). –

5

Qualsiasi funzione membro deve avere accesso agli altri membri dell'oggetto. Perché stai cercando di proteggerti da te stesso?

Gli elementi statici sono generalmente utilizzati con parsimonia, ad esempio metodi di fabbrica. Creerai una situazione che rende la prossima persona a lavorare con il tuo codice vai "WTF ???"

+1

Bene, diciamo che hai una funzione membro in cui non hai assolutamente bisogno di accedere a nessuna delle altre funzioni/variabili degli altri membri. Non sarebbe quindi opportuno limitare tale accesso utilizzando l'elettricità statica? So che sembra strano, ma usando l'argomento che potrebbe essere necessario l'accesso e qualche punto in cui il codice cambia, potrebbe essere usato come argomento contro le costanti in generale. –

+4

Spesso ti vuoi proteggere da te stesso. Questa è la ragione per cui esiste const (o final, o readonly). Questi modificatori segnalano l'intento e impediscono di utilizzare i dati in modi non previsti. Inoltre, per una funzione come "print_error", preferisco renderlo statico e passare in un flusso di output, quindi utilizzare implicitamente un flusso di input associato a un particolare oggetto. –

+0

E per quanto riguarda la reazione della prossima persona che visualizza il tuo codice, se documenti correttamente il codice (il tuo motivo per renderlo statico, come descritto sopra), i tuoi colleghi/colleghi dovrebbero capire. Proprio come con const. Quando vedo una costante o una funzione statica, cerco di capire perché la persona ha fatto quella distinzione.Il caso migliore è che lasciano una documentazione del perché. –

3

Non farlo. L'utilizzo di static come meccanismo di controllo degli accessi è un abominio barbarico.

Una ragione per non farlo è perché è strano. I programmatori di manutenzione avranno difficoltà a capire il tuo codice perché è così strano. Il codice manutenibile è un buon codice. Tutti ricevono i metodi const. Nessuno ottiene static-as-const. La migliore documentazione per il tuo codice è il codice stesso. Il codice di auto-documentazione è un obiettivo a cui dovresti aspirare. Non in modo che non sia necessario scrivere commenti, ma in modo che loro non debbano leggere loro. Perché sai che non lo faranno comunque.

Un altro motivo per non farlo è perché non si sa mai cosa porterà il futuro. Il tuo metodo print_error non ha bisogno di accedere allo stato della classe - ora. Ma posso vedere come potrebbe essere necessario un giorno. Supponiamo che la tua classe sia un involucro attorno a un socket UDP. A un certo punto nel mezzo della sessione, l'altra estremità sbatte la porta. Vuoi sapere perché. Gli ultimi messaggi inviati o ricevuti potrebbero contenere un indizio. Non dovresti scaricarlo? Hai bisogno di stato per quello.

Un motivo falso è che fornisce il controllo di accesso dei membri. Sì, lo fa, ma ci sono già dei meccanismi per questo. Supponiamo che tu stia scrivendo una funzione che vuoi essere sicura che non cambi lo stato dell'oggetto. Ad esempio, print_error non dovrebbe modificare alcuno stato dell'oggetto. Quindi, fare il metodo const:

class MyClass 
{ 
public: 
    void print_error(const unsigned int error_no) const; 
}; 

...

void MyClass::print_error(const unsigned int error_no) const 
{ 
    // do stuff 
} 

print_error è un metodo const, il che significa in modo efficace che il puntatore this è const. Non è possibile modificare alcun membro non mutable e non è possibile chiamare metodi diversi da const. Non è proprio questo ciò che vuoi?

+1

+1 per 'abominio barbarico' – JoshD

+1

Ma perché la specifica consente a tutte le funzioni membro 'static' allora, se non per averle riservate per le funzioni di supporto che non devono fare affidamento su altri membri della classe o usare variabili di classe (a parte una libreria di funzioni di supporto, forse ...)? –

+0

Vedere la mia precedente descrizione di vari livelli di accesso nella mia nuova sezione intitolata "Modifica 1". –

1

È certamente giusto dire che le funzioni di ambito globale, le funzioni membro statiche e le funzioni di amicizia non sono tra loro abbastanza ortogonali. In una certa misura, questo è in gran parte dovuto al fatto che sono destinati ad avere un significato semantico alquanto diverso per il programmatore, anche se producono un output simile.

In particolare, l'unica differenza tra un metodo membro statico e una funzione amico è che gli spazi dei nomi sono differenti, il membro statico ha un namespace di ::className::methodName e la funzione amico è appena ::friendFunctionName. Entrambi funzionano allo stesso modo.

Bene, in realtà c'è un'altra differenza, i metodi statici sono accessibili tramite puntatore indiretto, che può essere utile nel caso di classi polimorfiche.

Quindi la domanda è, la funzione appartiene come "parte" della classe? In tal caso, utilizzare un metodo statico. in caso contrario, inserire il metodo nell'ambito globale e renderlo un amico se potrebbe richiedere l'accesso alle variabili membro private (oppure no se lo fa)

Problemi correlati