diff options
-rw-r--r-- | doc/.ninja_deps | bin | 0 -> 16 bytes | |||
-rw-r--r-- | doc/.ninja_log | 2 | ||||
-rw-r--r-- | doc/build.ninja | 7 | ||||
-rw-r--r-- | doc/quick_cplusplus.md | 245 | ||||
-rw-r--r-- | doc/quick_cplusplus.pdf | bin | 0 -> 212718 bytes |
5 files changed, 254 insertions, 0 deletions
diff --git a/doc/.ninja_deps b/doc/.ninja_deps Binary files differnew file mode 100644 index 0000000..2afb5cc --- /dev/null +++ b/doc/.ninja_deps diff --git a/doc/.ninja_log b/doc/.ninja_log new file mode 100644 index 0000000..891c53f --- /dev/null +++ b/doc/.ninja_log @@ -0,0 +1,2 @@ +# ninja log v5 +0 770 1548439603 quick_cplusplus.pdf 5be4e5805f2d04b5 diff --git a/doc/build.ninja b/doc/build.ninja new file mode 100644 index 0000000..b8b5252 --- /dev/null +++ b/doc/build.ninja @@ -0,0 +1,7 @@ +pandocflags = --highlight-style tango + +rule pdf + command = pandoc $pandocflags -o $out $in + + +build quick_cplusplus.pdf: pdf quick_cplusplus.md diff --git a/doc/quick_cplusplus.md b/doc/quick_cplusplus.md new file mode 100644 index 0000000..411e0a3 --- /dev/null +++ b/doc/quick_cplusplus.md @@ -0,0 +1,245 @@ +--- +title: Modern C++ per chi conosce un po' di C, + spiegato di fretta da qualcuno senza alcuna qualifica per insegnare +author: Naoki Pross +--- + +# Introduzione +Ultimamente ho così poco da fare che ho deciso di scrivere un corso +relativamente spedito di C++. È sorprendente a cosa può portare la noia, non +trovate? Okay, iniziando seriamente prima devo presentarvi nella maniera più +spiccia possibile un paio di brutte cose. + +## Cosa serve per inziare +Non ho voglia di scrivere un corso di programmazione da *zero*, quindi do per +assunto che sappiate almeno le fondamenta di programmazione, cosa siano un +*compiler* o un *linker* e come funzioni il processo di compilazione del C, +siccome è praticamente lo stesso per il C++. Non vi ricordate? Ecco un corso +super accelerato: +``` +source code > compiler > object > linker > eseguibile +main.cpp > g++ > main.o > ld > my_program +``` +Ah e il codice è tutto in inglese, buona fortuna. + +## Nell'industria il C++ è un casino +Esistendo da troppo tempo (non quanto il C, ma quasi) ogni idiota sulla faccia +della terra ha pensato bene di creare una propria variante del C++. + +Fortunatamente di recente Bjarne Stroustrup, creatore del C++, ha iniziato +a cercare di salvare questo casino aggiornato la *C++ standard library*, +dando un paio di direttive su come scrivere il cosìdetto *Modern C++*, versione +$\geq$ 11. + +Quindi da bravo programmatore io in questo documento seguirò le direttive del +modern C++, ma sappiate che più o meno la maggior parte della gente non +rispetta queste regole complicando la vita a tutti, quindi preparatevi per +quando sarete fuori dalla scuola. + +## Documenti del C++ +Quindi è come il C, ma i file del codice sorgente si chiamano `.cpp` invece di +`.c`, giusto? Sarebbe bello; neanche su questo sono d'accordo le persone. +Esistono le estensioni `.cpp` e `.cc` per i sorgenti e `.hpp` e `.h` per gli +headers. Quale usare? `.cpp` e `.hpp` ovviamente. + +# Iniziamo con le fondamenta +Arrivando dal C o da un qualsiasi altro linguaggio di programmazione simile, +spero sappiate come funzionano le keywords `if`, `while`, `for`, `...` quindi +le saltiamo per passare alle novità. Prima però vi lascio un programma in C++ +minimo, che non fa assolutamente niente. +```C++ +int main(int argc, char *argv[]) { + return 0; +} +``` +Che dovrebbe lasciarsi compilare con un comando come il seguente (o con un +qualche maledetto bottone nella vostra grafica, se la preferite). +```sh +$ g++ -Wall -Werror -std=c++11 -o hello hello.cpp +``` +Favoloso. Nulla di nuovo, giusto? + +## Scope +Una cosa importantissima in C++ è capire cosa è uno *scope*, traducibile +dall'inglese come ambito, scopo o raggio. +```C++ +{ + int hello_there = 10; +} +``` +Lo *scope* della variabile `hello_there` sono quelle parentesi graffe. Perché +come sapete, una volta fuori dalle parentesi `hello_there` cessa di esistere, +va *out of scope*. Quindi praticamente ogni elemento come un `if`, un `while` o +una funzione creano uno *scope*, utilizzando le parentesi graffe. + +Uno scopo eredita l'accesso alle variabili del suo scopo parente, mentre non è +possibile il contrario, ossia: +```C++ +{ + int x = 10; + { + int y = 1; + // we can access 'x' from the outer scope + x += 10; + } + // but we CANNOT access this variable 'y' + // from the inner scope above + // this DOES NOT compile + y = 10; +} +``` +Tra l'altro, se ve lo steste chiedendo, è assolutamente valido mettere delle +parentesi `{}` senza alcuna *keyword* come `while` o `if` e si usa per ordinare +il codice gestendo gli scopi o *lifetime* delle variabili. + +## Namespaces +Un problema del C è che siccome, giustamente, non possono esserci funzioni o +tipi con lo stesso nome il codice diventa orribile in fretta. Per esempio è +tipico (e corretto) prependere le funzioni e i tipi di una libreria con il nome +della libreria. Esempio: +```C +GtkWidget* gtk_window_new(GtkWindowType type); +``` +Ma non essendo una cosa obbligatoria, spesso il codice diventa disordinato +quando ci si dimentica di applicare questa regola. + + +Si introducono dunque i `namespace`, che non fanno altro che raggruppare varie +parti di codice sotto un nome comune. Permettendo inoltre funzioni e tipi con +lo stesso nome! Per esempio: +```C++ +namespace rs232 { + int open(unsigned device_id); +} +``` +```C++ +namespace file { + const int WRITE = 0; + int open(const char *path, int mode); +} +``` +Che successivamente si possono utilizzare con la seguente sintassi. +```C++ +// calls open() from the 'rs232' namespace +rs232::open(0); + +// calls open() from the 'file' namespace +int fd = file::open("/tmp/log.txt", file::WRITE); +``` +Esiste dunque un `namespace` che contiene la *standard library* (spesso +chiamata anche STL) che giustamente è chiamato `std`. `std` contiene molte cose +molto utili come per esempio la `std::string`. + +## Allocazione di memoria dinamica +Come sapete è spesso utile se non necessario allocare della memoria "dinamica", +ossia non controllata a tempo di compilazione. +In C esistono le funzioni `malloc()` e `free()` per richiedere e liberare della +memoria. In C++ la funzione è stata integrata con delle *keywords* quali `new` +e `delete`, che si usano come segue. +```C++ +// C: int *data = malloc(10 * sizeof(int)) +int *data = new int[10]; +``` +```C++ +// C: free(data); +// data = NULL; +delete data; +``` + +## References +I puntatori del C sono molto utili, non possiamo negarlo, ma come tutti sanno +non sono esattamente comodi. Per essi e i loro problemi abbiamo un intero +documento dedicato (Pointers, the best worst feature of C). + +Dunque malgrado in C++ i puntatori esistono e funzionano esattamente come in C, +esiste un nuovo concetto di *referenza*. Vediamo da dove originano con il +solito esempio stupido in C. +```C +void increment(int *v) +{ + if (v == NULL) + return; + + (*v)++; +} +``` +Che si utilizzerebbe come segue. +```C +int x = 10; +increment(&x); +// 'x' is now 11 +``` +Questa funzione è sorprendentemente complicata rispetto alla semplicità di ciò +che deve fare. Insomma non sarebbe più comodo se non si dovesse controllare che +non è `NULL` e se non si dovesse dereferenziare il puntatore? Qualcosa come: +```C++ +void increment(int& v) { + v++; +} +``` +Ecco, questa è una referenza in C++, come un puntatore ma sempre valido e che +non si deve dereferenziare. E non necessita nemmeno della `&` per convertire +una variabile in puntatore quando si chiama la funzione. +```C++ +int x = 10; +increment(x); // no need to take the address +// 'x' is now 11 +``` +Questo ovviamente era il caso di un argomento (parametro) di una funzione, ma +le referenze possono esistere anche come i puntatori. Ma non mi pare di averle +mai viste utilizzate in questo modo. +```C++ +int x = 10; +int& y = x; + +y *= 2; +// 'x' (and 'y' referencing it) is now 20 +``` + +## Overloading +La parola *overloading*, tradotta dall'inglese potrebbe essere qualcosa come +"sovraccaricare" ed è un concetto estremamente utile. Esso serve a risolvere +un problema facile da riscontrare. Mettiamo per esempio che stiamo creando +una libreria integrante delle funzioni matematiche. +```C++ +namespace math { + int pow(int base, int exponent); + double pow(double base, double exponent); +} +``` +Volendo avere le funzioni che funzionano sia per numeri interi che per numeri +a virgola mobile a doppia precisione, abbiamo due funzioni con lo stesso nome! + +In C si creerebbero degli abomini come `powi()` e `powdf()` per differenziare +i due. Ma in C++ non è necessario! Il codice sopra è assolutamente valido +e il compiler è abbastanza intelligente da capire quale dei due si vuole +utilizzare quando la funzione è chiamata. +```C++ +// uses function with signature +// int math::pow(int, int) +int a = math::pow(2, 3); // 8 + +// uses function with signature +// double math::pow(double, double) +double v = math::pow(4.0, 0.5); // 2 +``` +Cosa succede se mischiamo le due cose? +```C++ +double mixed = math::pow(2, 0.5) // ?? +``` +Esempio con `g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0` +```sh +ex.cpp:22:37: error: call of overloaded ‘pow(int, double)’ is ambiguous + double mixed = math::pow(4, 0.5); + ^ +ex.cpp:4:9: note: candidate: int math::pow(int, int) + int pow(int base, int exponent) { + ^~~ +ex.cpp:13:9: note: candidate: int math::pow(double, double) + int pow(double base, double exponent) { + ^~~ +``` +Giustamente non compila, perché il compiler non sa quale delle due funzioni si +vuole utilizzare. Ci propone però le varianti che ha trovato "`note: +candidate`" che potrebbero essere valide. + diff --git a/doc/quick_cplusplus.pdf b/doc/quick_cplusplus.pdf Binary files differnew file mode 100644 index 0000000..ac74aa3 --- /dev/null +++ b/doc/quick_cplusplus.pdf |