Nascondere e incapsulamento in C ++
Tutti abbiamo sentito parlare dell’incapsulamento delle informazioni nelle lingue Orientato agli oggetti e in C ++. Vediamo qui di cosa consiste e alcuni “trucchi” che possiamo fare nel caso specifico di C ++ e che di solito non vengono nei libri di questa lingua (anche se nei libri su modelli di design).
I punti che vedremo sono:
- Attacco dei tramplers in una classe
- Importanza di lanegnaleLolational per compilare in c ++
- Encapsulation attraverso le interfacce
incapsulamento degli attributi di una classe
Prima di tutto, dovrebbe essere chiaro che l’incapsulamento, proprio come qualsiasi bene L’abitudine di programmazione (come non mettere fuori, commentare, ecc.) È utile per il codice che può essere in seguito riutilizzato o modificato, da altre persone o da se stessi. Se faccio un programma marziano e non ho mai pensato di toccarlo di nuovo, non importa quanto lo faccio con Gouts e senza commentare mentre mi trovo mentre lo sto facendo e funziona. Pagherò questo “peccato” se entro due mesi posso pensare di migliorarlo o voglio riutilizzare qualcosa dal suo codice per un altro programma.
I Comment questo perché l’incapsulamento, ha portato alla fine, come è il caso dell’endpoint delle interfacce, semplifica la programmazione un po ‘più complicata (devi fare più lezioni). Questo sforzo è premiato solo se il codice è molto grande (evitando ricompilati inutili) o sarà riutilizzato in futuro (possiamo estrarre le classi con meno dipendenze da altre classi). Detto questo, andiamo in argomento.
Qualsiasi corso di orientamento degli oggetti ci dice che è meglio mettere gli attributi di una classe protetta o privata (mai pubblica) e accedervi attraverso metodi pubblici che abbiamo messo in classe. Vediamo il motivo. Supponiamo, ad esempio, che chiedi un programma che ti permette di portare un elenco di persone con le date di nascita. Tra le altre cose, abbiamo deciso di farci la nostra classe di data con diversi metodi meravigliosi come segue.
int anho; // l’anho con quattro figure, ad esempio. 2004
Int Mese; // il mese, da 1 a 12
int giorno; // il giorno, da 1 a 31
void metodoMaravilloso1 ();
void metodoMaravillos2 ();
};
Abbiamo già fatto la classe. Ora facciamo il resto del codice e in diverse migliaia di linee di codice usiamo direttamente cose come questa.
UNACCHA.ANHO = 2004;
UNACCHA.MES = 1;
UNACCHA.DIA = 25;
Alla fine abbiamo finito il nostro programma e tutto funziona alla grande. Alcuni giorni dopo ci dicono che il programma manterrà le Tropecies Mille persone e che prendono molti file, piuttosto che vedere se possiamo fare qualcosa per rimediare. Wow, memorizziamo una data con tre numeri interi. Se utilizziamo il formato della maggior parte dei computer, in cui la data è il numero di secondi dal 1 ° gennaio 1970 (che ci restituisce il tempo () Funzione), è sufficiente un numero intero.
Totale, quali mani vengono cambiate, modificate la nostra classe in modo che abbia quanto segue:
/ * Commentato da PorineFial
Intanho; Intmes;
INTDIA; * /
longnumerseconds;
voidmetmetodomaravilloso1 ();
void metodoMaravillos2 ();
};
è già stato eseguito il facile. Ora devi solo passare attraverso le Tropecies Mille linee di codice cambiando i nostri incarichi e letture ai tre numeri interi precedenti del nuovo lungo.
sarebbe stato molto meglio se avessimo fatto questi tre numeri interi e metodi protetti per accedervi. Qualcosa come questo
Void Tomafecha (int anho, INT mese, INTDIA);
int Dameanho ();
int Dannemes ();
int Damedia ();
void metodoMaravilloso1 ();
void metodoMaravillos2 ();
Protetto:
int anho; // l’anho con quattro figure, ad esempio. 2004
Int Mese; // il mese, da 1 a 12
int giorno; // Il giorno, da 1 a 31
};
Se ora dobbiamo fare lo stesso cambiamento, basta modificare gli attributi protetti. I metodi TomaXXX () e Damexxx () sono mantenuti in termini di parametri e valore restituito, ma il suo codice interno viene modificato per rendere l’anno, mese e giorno in un secondo livello e a testa in giù. Il resto del codice non deve toccarlo affatto.
È ancora meglio fare gli attributi privati che protetti. Rendendoli protetti, le classi delle figlie (coloro che ereditano dalla data) possono accedere direttamente a questi attributi. Quando facciamo il cambiamento per un lungo, dobbiamo anche modificare il codice delle classi delle figlie. Se gli attributi sono privati e costringiamo le classi delle figlie per accedervi attraverso i metodi, non dovremo nemmeno cambiare il codice di queste classi di queste figlie.
L’accesso tramite i metodi è meno efficiente di farlo direttamente, quindi sebbene seguendo il principio di occultamento è meglio apportare attributi privati, per efficienza in alcuni casi è forse meglio renderli protetti (o persino pubblici ) Per rischiare di cambiare più linee di codice in caso di cambiamento.
Quando possibile gli attributi di una classe privata.
Importanza dell’orcapsulamento in c ++
con ciò che viene contato finora evitiamo Devo cambiare codice in caso di modifica dei parametri.
Nel caso di calcestruzzo di C ++ c’è un piccolo problema aggiuntivo. È abbastanza normale rendere le classi definiscono per mezzo di due file. Nel caso della classe data avremmo un date.h con la definizione della classe e un date.cc (o .cpp) con il codice dei metodi di classe. Quando vogliamo usare la classe di data, di solito facciamo il nostro #include < data.h >.
Qualsiasi processo di compilazione efficiente (come Linux renda l’utilità e immagino che il Visual C ++) sia abbastanza pronto per ricompilare solo quei file che devono essere ricompilati. Cioè, se abbiamo già il nostro progetto compilato e riprodurmo un file, il compilatore compilerà solo quel file e tutti coloro che dipendono da lui. Questa caratteristica è molto importante in progetti di grandi dimensioni (con molti file e molte linee di codice), per salvare il tempo di compilazione ogni volta che facciamo una modifica (ho lavorato su progetti che mi ci sono voluti per compilare da zero intorno a 4 ore).
Qual è il problema? Il problema è che se decidiamo, ad esempio, cambiamo di nuovo l’attributo privato della classe data per qualcos’altro, dobbiamo toccare il file data.h. Questo farà tutti i file che eseguino #include < data. Quella a turno è #include. Bene, così via.
La soluzione è evidente, posizionare il meno possibile alla data. H, in particolare le variabili #Define e globali che non sono necessarie da vedere da altre classi.
Ad esempio, la nostra classe di data potrebbe avere alcuni #Define per indicare che è il numero minimo e massimo del mese. È meglio collocare questi #Define in data. CC anziché data. H, a meno che qualcuno non possa vederli.
#Define mes_minimo 1
#Define mes_maximo 12
Quando possibile, mettere Il # definisce, tipi di definizione, costanti globali, ecc., All’interno delfichero.cc
incapsulation attraverso le interfacce
Abbiamo una cosa rimasta. Perché dobbiamo ricompilare molte cose se cambiamo un attributo privato della classe? L’ideale sarebbe essere in grado di cambiare le cose interne della classe senza dover ricompilare qualsiasi altra cosa, dopo tutto, l’attributo è privato e nessuno lo usa direttamente.
È abbastanza comune nella programmazione orientata agli oggetti l’uso delle interfacce per rendere le classi dipendono l’una dall’altra. Nel caso di C ++, l’uso delle interfacce è anche utile per evitare ricompilati non necessari.
Un’interfaccia non è più di una classe in cui sono definiti i metodi pubblici necessari, ma non sono implementati. Quindi la classe concreta che vogliamo effettuare ereditare da quell’interfaccia e implementa i suoi metodi.
Nel nostro caso, possiamo creare una classe di interfaccia, con metodi pubblici virtuali puri (nessun codice). Quindi la classe di data eredita dall’interfaccia e implementa tali metodi.
nel file di interfaccia. Virtual Int Dameanho () = 0;
Virtual INT DAMEMES () = 0;
Virtual INT DAMEDIA () = 0; Virtual void Methodomaravilloso1 () = 0; Virtual void Methodomaravillos2 () = 0;
};
Al momento, non esisteva nemmeno un’interfaccia. CC
La classe di data è ancora la stessa, ma ereditata dall’interfaccia.
Data di classe: Interfaccia pubblica> Pubblico:
Void Tomafa (Int Anho, Int Mese, Intdia);
int Dameanho ();
int Dannemes ();
int Damedia ();
void metodoMaravilloso1 ();
void metodoMaravillos2 ();
Protetto:
int anho; // l’anho con quattro figure, ad esempio. 2004
Int Mese; // il mese, da 1 a 12
int giorno; // Il giorno, da 1 a 31
};
Ora, tutti coloro che necessitano di una data, devono avere un puntatore all’interfaccia invece di oggi. Qualcuno installerà la data e lo manterrà in quel puntatore. Cioè, potremmo fare qualcosa come questo
#include < Interfaccia. >
…Interfaccia infetta * Uno-= null;
…
istacho = nuova data ();
UNACCHA- > TOMACCA (2004, 1, 27);
…
Elimina sgannello;
UNACCHA = NULL;
Se sembriamo un po ‘, non abbiamo ancora risolto nulla, a meno che non abbia complicato la questione. Quello che ha bisogno di questo codice deve fare ora #include sia interfacceffe.h e data.h. Se tocchiamo qualcosa in data. H, questo codice verrà ricombito.
Questo codice ha bisogno #include < data.h > per essere in grado di eseguire la data della data. Devi cercare come evitarlo. Di solito è anche abbastanza normale effettuare una classe (o utilizzare la stessa interfaccia se la lingua lo consente, come è il caso di C ++) di mettere un metodo statico che il nuovo e restituirlo.
Nel caso di Java, mettendo questo metodo, non avremmo più un’interfaccia, ma una classe. Fare informato data ereditato limita gli Stati Uniti per non ereditare da qualsiasi altra cosa (Java non supporta più eredità). Se questo è ammissibile, possiamo farlo in quel modo. Se abbiamo bisogno di quella data ereditata da un’altra classe, invece di mettere il metodo statico nell’interfaccia, dobbiamo fare un terzo generatore separatamente con questo metodo statico.
Nel nostro esempio C ++, la classe di interfaccia sarebbe rimasta.
{
Pubblico:
Staticinterfacefacea * DamenuevaFecha ();
Virtual Voidtomacy (Intanho, Intmes, Int Day) = 0; Virtual Int Dameanho () = 0;
Virtual INT DAMEMES () = 0;
Virtual INT DAMEDIA () = 0; Virtual void Methodomaravilloso1 () = 0; Virtual void Methodomaravillos2 () = 0;
};
Ora abbiamo bisogno di un’interfaccia. cc. All’interno di lui avremo
Data.
}
Il codice che in precedenza utilizzato il puntatore sull’interfaccia sarebbe ora
…
Interfaccia * UNACCHA = NULL;
…
UNACCHA = Interfaccia infettata :: Damenuecha ();
UNACCHA- > TOMACCA (2004, 1, 27);
…
Elimina sgannello;
UNACCHA = NULL;
Come vediamo, solo il #include di interfaceefeaques.h e questo non include data.h (interfaccia. cc, non il .h). Abbiamo reso questo codice non vedere affatto alla data. Ora possiamo giocare senza dare un’occhiata alla data. H, che questo codice non ha bisogno di essere ricompilato.
Un ulteriore vantaggio è che è possibile modificare la data della data per un’altra data2 in fase di runtime. Sarebbe sufficiente mettere un attributo statico nell’interfaccia per indicare quale data di classe vogliamo e rendere il metodo Damenuevacha () Istantie e restituisce l’uno o l’altro a seconda dell’attributo.
Uso Interfacce Paquelas Clasque Pianta che è possibile modificare Del Devoroyectoo de Developtoo de Develope Order.
Questo meccanismo ottiene un’istanza di una classe attraverso un metodo statico e Un’interfaccia, per non dipendere dalla classe specifica, penso che nel mondo dei modelli di progettazione sia il modello di fabbrica.