Dichiarazioni, Funzioni e Namespaces
Le Declaration Statements (Dichiarazioni) introducono identificatori — come funzioni, classi, template e namespace — all’interno del programma.
(Anche lo static_assert introdotto nel Capitolo 6 rientra formalmente nella categoria delle dichiarazioni).
Funzioni: Dichiarazione vs Definizione
Section titled “Funzioni: Dichiarazione vs Definizione”La Dichiarazione di una funzione (o prototipo / firma) ne specifica gli input e gli output. Non ha bisogno di specificare il nome dei parametri, ma solo i tipi.
void randomize(uint32_t&); // DichiarazioneLa Definizione di una funzione include sia la dichiarazione che il blocco di codice (il corpo) della funzione stessa.
Il C++ (a differenza di linguaggi di scripting lineari) permette di dichiarare funzioni e usarle nel codice prima ancora di averle definite. Finché il compilatore trova il prototipo, saprà come validare la chiamata e confiderà nel fatto che la definizione verrà fornita altrove (magari alla fine del file, o in un altro file .cpp processato dal linker).
Questo pattern è utilissimo (e onnipresente) nei progetti reali che usano molteplici file, in quanto la dichiarazione va solitamente nell’Header file (.h), mentre la definizione cicciotta va nel Source file (.cpp).
I Namespaces (Spazi dei Nomi)
Section titled “I Namespaces (Spazi dei Nomi)”I progetti reali importano centinaia di librerie esterne. È matematicamente probabile che qualcuno prima di te abbia scritto una classe chiamata Database o User. Per prevenire disastrosi conflitti di nome (Naming Conflicts), il C++ incapsula gli identificatori nei Namespaces.
Per impostazione predefinita, tutto finisce nel global namespace. Ma possiamo inserire il nostro codice in stanze chiuse:
namespace BroopKidron13 { namespace Shaltanac { enum class Color { Mauve, Pink, Russet }; }}// Sintassi moderna (C++17) molto più compatta:namespace BroopKidron13::Shaltanac { enum class Color { Mauve, Pink, Russet };}Per accedere al colore Mauve da fuori, dovrai specificare il percorso assoluto usando l’operatore di scope-resolution ::. Il nome diventerà enorme: BroopKidron13::Shaltanac::Color::Mauve.
Le Direttive using
Section titled “Le Direttive using”Per alleviare il tunnel carpale, puoi usare la direttiva using per importare un determinato simbolo (o l’intero namespace) nel tuo scope corrente.
PERICOLO ASSOLUTO: Non inserire MAI
using namespace XYZ;all’interno di un file Header (.ho.hpp). Qualsiasi altro file.cppdel progetto che includerà il tuo header si ritroverà l’intero global namespace “inquinato” e fuso con XYZ, causando conflitti di nome catastrofici in punti inaspettati. Usalo solo internamente ai blocchi o nei.cpp.
Type Aliasing (Alias di Tipo)
Section titled “Type Aliasing (Alias di Tipo)”Se il nome di un tipo è troppo lungo e scocciante da digitare ripetutamente, puoi creare un Type Alias (Alias di tipo). Usa la keyword using seguita da un =.
È l’evoluzione C++ del vecchio typedef del C.
L’Alias agisce come un sinonimo e non genera un nuovo tipo a livello di runtime.
// Rinomina un array in modo leggibileusing String = const char[260];
// Semplifica path chilometriciusing ShaltanacColor = BroopKidron13::Shaltanac::Color;
int main() { String message { "Il mio colore preferito è..." }; ShaltanacColor my_color = ShaltanacColor::Mauve;}Gli Alias brillano in sinergia con i Template, dove puoi effettuare “l’applicazione parziale”: ovvero definire un alias che congela il primo parametro di template lasciando dinamico il secondo, abbattendo la verbosità del codice meta-programmato.