-
Notifications
You must be signed in to change notification settings - Fork 0
/
Concetti_Intermedi.tex
3761 lines (2772 loc) · 144 KB
/
Concetti_Intermedi.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
% ----------------------------- CONCETTI INTERMEDI -----------------------------------
\chapter{Concetti Intermedi}
%Possibili argomenti aggiuntivi di questo capitolo:
%TODO: sttrutture dati cosa sono? Strutture dati: array, linked list, stack, queue. E anche Abstract Data Types (ADT): list, stack, queue. map usa Red Black Tree.
%TODO: <functional>?
%TODO: alignas, alignof?
% -------------------------- SECTION: INTRODUZIONE -----------------------------------
\section{Introduzione}
\textsf{\small In questo capitolo, tratterò argomenti non necessariamente più complicati, ma che non considererei basi. } \\
\textsf{\small In questo capitolo vedremo ulteriori concetti riguardo le classi, il polimorfismo, le varie tipologie di costruttori, la programmazione generale, le lambdas, la programmazione funzionale e molto altro ancora..} \break
% -------------------------- SECTION: STL --------------------------------------------
%TODO: forse è quasi da mettere dopo i templates visto che bisogna sapere cosa sono i templates.
\section{STL | Standard Template Library}
\textsf{\small \textbf{Definizione: } La \textbf{Standard Template Library} (\emph{STL}) è un insieme di classi template che forniscono le classiche strutture dati e funzioni come: liste, stacks, arrays, eccetera.} \break
\textsf{\small È una libreria di contenitori (containers) di classi, algoritmi e iteratori. È una libreria generalizzata, i suoi componenti sono parametrizzati.} \\
\textsf{\small È stata sviluppata separatamente e poi sottoposta al \textbf{C++ standard commitee} per essere considerata e per dare loro la possibilità di adottarla nel linguaggio.} \break
\textsf{\small \textbf{L'STL ha quattro componenti: } } \\
\begin{itemize}
\item \textsf{\small Algoritmi}
\item \textsf{\small Contenitori}
\item \textsf{\small Funzioni}
\item \textsf{\small Iteratori}
\end{itemize}
\subsection{Che cos'è \#include <bits/stdc++.h>?}
\textsf{\small \textbf{Definizione: } È un header file che include tutti gli header files della \textbf{STL}.} \\
\textsf{\small \textbf{Non} dovrebbe essere usato perché: } \\
\begin{itemize}
\item \textsf{\small è \emph{lazy} (pigro).}
\item \textsf{\small è un header del compilatore \emph{GCC} e quindi \textbf{non} è portabile, ovvero potrebbe \textbf{non} andare in altri.}
\item \textsf{\small non sai che cosa fa perché i suoi contenuti \textbf{non} sono standard.}
\item \textsf{\small ogni header file dovrebbe essere \emph{parsato} il che renderebbe tutto più lento.}
\item \textsf{\small rende il codice \textbf{non} portabile.}
\end{itemize}
% -------------------------- SECTION: TEMPLATES --------------------------------------
\newpage
\section{Templates}
\textsf{\small Immaginiamo di avere un codice, esempio questo:} \\
\begin{lstlisting}
const int& max(const int& a, const int& b)
{
return a > b ? a : b;
}
\end{lstlisting}
\textsf{\small Però ora se noi volessimo utilizzare questa funzione per i double, dovremmo copiarla e cambiare la tipologia da int a double.} \\
\begin{lstlisting}
const int& max(const int& a, const int& b)
{
return a > b ? a : b;
}
const double& max(const double& a, const double& b)
{
return a > b ? a : b;
}
\end{lstlisting}
\textsf{\small C'è un problema: se ora volessimo usare la stessa funzione, ma con i float? o con i char? Certo potremmo fare dei casts, ma così perderemmo dei dati, ma soprattutto ripeteremmo lo stesso codice più e più volte semplicemente per avere la stessa identica funzione, ma per tipologie diverse.} \\
\textsf{\small Inoltre, fare questo, continuare a ripetere lo stesso codice, violerebbe un'importante principio di programmazione, ovvero \textbf{DRY}: \emph{Don't repeat yourself}, in italiano, non ripeterti.} \break
\textsf{\small Vogliamo cercare di ripetere lo stesso codice \textbf{il meno possibile} e \textbf{cercare di riutilizzare} codice che già abbiamo per altre funzionalità.} \\
\textsf{\small Quindi, c'è un modo migliore? Possiamo evitare di ripetere di scrivere lo stesso codice più e più volte? Si e Si! E facciamo questo attraverso i \textbf{templates}!} \break
\textsf{\small \textbf{Definizione:} I \textbf{templates} sono la fondazione della programmazione generale che riguarda lo scrivere codice che è indipendente dalla tipologia. } \\
\textsf{\small Quindi un \textbf{template} ti permette di creare uno stampino che funziona con qualsiasi tipo di variabile.} \\
\textsf{\small Come facciamo a dire al compilatore che vogliamo usare una variabile generica? Usiamo \textbf{typename} per dire che l'identificatore che segue è una tipologia e lo mettiamo all'interno del "diamantino", ovvero <>.} \\
\textsf{\small }
\begin{lstlisting}
template <tipologia> tipoDiRitorno nomeDellaFunzione(lista dei parametri)
{
// corpo della funzione.
}
// Quindi usiamo una tipologia generica e la indichiamo con T, ma avremmo potuto usare qualsiasi altra lettera.
template<typename T>
const T& max(const T& a, const T& b)
{
return a > b ? a : b;
}
int x = 5, y = 3;
std::cout << "Max tra due int: " << max(a, b) << std::endl; // Output: Max tra due int: 5
double d1 = 3.69, d2 = 7.89;
std::cout << "Max tra due double: " << max(a, b) << std::endl; // Output: Max tra due double: 7.89
// Fate attenzione che se state usando 'using namespace std', avrete due funzioni chiamate max, una della libreria standard e l'altra questa in questo esempio.
// In quel caso vi conviene rinominare la vostra funzione in qualcos'altro o semplicemente con la m MAIUSCOLA (Max).
\end{lstlisting}
\textsf{\small Questo, può naturalmente essere fatto anche con le classi ed altro..} \\
\textsf{\small Questa è una funzionalità, come abbiamo potuto vedere in questo semplice esempio, di quanto possono essere utili i templates.} \\
\begin{figure}[ht]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/template.png}
\caption{Template}
\label{fig:template}
\end{figure}
% -------------------------- SECTION: VECTOR -----------------------------------------
%TODO: emplace_back
\section{std::vector<>}
\textsf{\small \textbf{Definizione:} Un \textbf{vector} è un contenitore rappresentante un array che può cambiare in size (spazio). Sono degli array dinamici.} \\
\textsf{\small I vectors memorizzano i dati in locazioni contigue di memoria e permettono l'accesso diretto a qualsiasi elemento usando l'operatore []. Supportano la riduzione e l'ampiamento dello spazio a runtime (ovvero eseguite mentre il tuo programma è in esecuzione).} \\
\textsf{\small La classe vector fa uso dei template così che possiamo eseguirla con qualsiasi tipo. Per poterla usare avremo bisogno di importare \textbf{\#include <vector>}.} \\
\begin{lstlisting}
#include <iostream>
#include <vector>
std::vector<int> v{ 1, 3, 7, 8};
std::vector<int> v2 = v; // Oppure potevamo scrivere std::vector<int> v2(v);
v2.push_back(9); // Aggiungiamo un elemento.
std::cout << "v size: " << v.size() << std::endl; //Output: v size: 4
std::cout << "v2 size: " << v2.size() << std::endl; //Output: v2 size: 5
\end{lstlisting}
\textsf{\small Inoltre, la classe vector mette a disposizione tante altre funzioni per la loro manipolazione.} \\
\textsf{\small P.S.: Da non confondere con i vettori in matematica|fisica.} \break
% -------------------------- SECTION: ITERATORI --------------------------------------
\newpage
\section{Iteratori}
\textsf{\small \textbf{Definizione: } Gli \textbf{iteratori} sono degli oggetti (come puntatori) che puntano ad un elemento all'interno di un contenitore. Usiamo gli \textbf{iteratori} per muoverci nel contenitore } \break
\textsf{\small Ci sono diversi tipi di iteratori: }
\begin{itemize}
\item \textsf{\small \textbf{Input Iterators} : Sono i più deboli fra tutti per via delle loro limitate funzionalità. Può essere usato solo in algoritmi single-pass ovvero quelli che processano il contenitore in modo sequenziale.}
\item \textsf{\small \textbf{Output Iterators} : Anch'essi sono molto limitati. Possono essere usati negli algoritmi single-pass, ma non per accedere agli elementi, ma per essere assegnati agli elementi.}
\item \textsf{\small \textbf{Forward Iterator} : Sono più in alto nella gerarchia rispetto agli input ed output e possiedono tutte le funzionalità di questi ultimi due, ma possono anche muoversi in avanti ed anch'essi di una posizione alla volta.}
\item \textsf{\small \textbf{Bidirectional Iterators} : Possiedono tutte le funzionalità degli forward iterators, ma possono muoversi in entrambe le direzioni.}
\item \textsf{\small \textbf{Random-Access Iterators} : Sono gli iteratori più potenti. Non sono limitati dal solo poter muoversi in modo sequenziale, ma possono accedere in maniera casuale a qualsiasi elemento dentro ad un contenitore. Sono quelli che hanno le stesse funzionalità dei puntatori.}
\end{itemize}
\pagebreak
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/iterators.jpg}
%\caption{Iteratori}
\label{fig:iterators}
\end{figure}
\vspace{-3.69cm}
\textsf{\small È sempre meglio usare gli \textbf{iteratori} per iterare tra i contenuti di un contenitore così da evitare di usare l'operatore \textbf{[]} per accedere agli elementi. Inoltre per ottenere la fine di un contenitore con gli \textbf{iteratori} possiamo semplicemente usare la funzione \textbf{end()} al posto di utilizzare lo spazio occupato. } \break
\textsf{\small Possono essere utili per la riusabilità del codice, visto che anche se cambiamo vettore, il codice riguardante gli \textbf{iteratori} non dovrebbe cambiare.} \\
\textsf{\small Gli \textbf{iteratori} ci permettono una manipolazione dinamica dei contenitori, fornendoci la possibilità di aggiungere e rimuovere elementi in modo dinamico a nostro piacimento.} \break
\textsf{\small Per poter usare gli iteratori è necessario includere \textbf{\#include <iterator>}.} \\
\begin{itemize}
\item \textsf{\small \textbf{begin()} : Restituisce la posizione iniziale del contenitore.}
\item \textsf{\small \textbf{end()} : Restituisce la posizione finale del contenitore.}
%\item \textsf{\small \textbf{} :}
\end{itemize}
\begin{lstlisting}
#include <iostream>
#include <iterator>
std::vector<int> v = { 9, 6, 3};
// Dichiaro un iteratore.
std::vector<int>::iterator it;
for(it = v.begin(); it < v.end(); it++)
{
std::cout << "Elemento: " << *it << std::endl;
}
// Output: stampa uno ad uno gli elementi del vettore.
\end{lstlisting}
\begin{itemize}
\item \textsf{\small \textbf{advance()} : Incrementa la posizione dell'iteratore fino all'argomento passato come parametro.}
\item \textsf{\small \textbf{next()} : Restituisce un nuovo iteratore dopo aver avanzato di tot posizioni menzionate nell'argomento.}
\item \textsf{\small \textbf{prev()} : Restituisce un nuovo iteratore dopo essere retrocesso di tot posizioni menzionate nell'argomento.}
\item \textsf{\small \textbf{inserter()} : Per inserire elementi ad qualsiasi posizione nel contenitore. Prende due argomenti: il contenitore e l'iteratore alla posizione in cui l'elemento deve essere inserito.}
\end{itemize}
\begin{lstlisting}
#include <iostream>
#include <iterator>
std::vector<int> v = { 9, 6, 3};
std::vector<int> v2(2, 5, 8);
std::vector<int>::iterator it = v.begin();
std::advance(it, 2);
std::cout << "Elemento dell'iteratore dopo advance: " << *it << std::endl; // Output: Elemento dell'iteratore dopo advance: 3
std::prev(it, 2);
std::cout << "Elemento dell'iteratore dopo prec: " << *it << std::endl; // Output: Elemento dell'iteratore dopo prec: 9
std::next(it, 1);
std::cout << "Elemento dell'iteratore dopo next: " << *it << std::endl; // Output: Elemento dell'iteratore dopo next: 6
// Copio gli elementi di 1 vettore nell'altro usando inserter
// Inserisco gli elementi di v2 in v alla posizione a cui puntava l'iteratore it.
std::copy(v2.begin(), v2.end(), std::inserter(v, it));
for(int &x : v)
{
std::cout << "Elemento: " << x << std::endl;
}
// Output: Gli elementi del vettore con gli elementi aggiunti.
\end{lstlisting}
\subsection{Range-based for loop | Foreach}
\label{foreach}
\textsf{\small Questo tipo di loop, usufruisce sempre della keyword \textbf{for}, itera su un contenitore.} \\
\begin{lstlisting}
#include <iostream>
#include <vector>
for(tipo nomeVariabile : nomeContenitore)
{
// Corpo del range-based for loop o foreach
}
std::vector<int> v{ 3, 7, 9, 12};
// La i (avremmo potuto darci qualsiasi altro nome apparte lo stesso nome del contenitore) è la variabile che rappresenta un elemento del contenitore v ad ogni iterazione del ciclo.
// Quindi alla prima iterazione i corrisponderà al primo elemento del contenitore, alla seconda il secondo elemento, così via finchè i corrisponderà all'ultimo elemento + 1 del contenitore v.
for(const int &i : v)
{
std::cout << i << " ";
}
//Output: 3 7 9 12
\end{lstlisting}
\textsf{\small i è la variabile che rappresenta ad ogni iterazione del ciclo un elemento del \emph{container} in questo esempio.} \\
\textsf{\small Se non si conosce la tipologia del contenitore o per far prima si può anche utilizzare la keyword \textbf{auto}.} \break
\textsf{\small Questo è un loop molto efficiente quando utilizzato con i contenitore della libreria standard.} \\
\subsubsection{Ottenere l'elemento per valore o per referenza a costante}
\textsf{\small Quando è meglio utilizzare il \textbf{range-based for loop} per valore, per referenza e costante? } \\
\begin{itemize}
\item \textsf{\small \textbf{auto x} : quando si vuole lavorare con le copie.}
\item \textsf{\small \textbf{auto \&x} : quando si vuole lavorare con gli elementi originali e li si vuole modificare.}
\item \textsf{\small \textbf{const auto \&x} : quando si vuole lavorare con gli elementi originali, ma non si vuole modificarli.}
\end{itemize}
%TODO: Iterable Interface?
\subsection{begin vs cbegin}
\textsf{\small \textbf{begin} restituisce un \emph{iteratore} all'inizio mentre \textbf{cbegin} restituisce un \emph{const\_iterator} all'inizio. } \\
\textsf{\small Quindi, \textbf{begin} che restituisce un \emph{iterator} permette di modificare ciò a cui si sta puntando, mentre \textbf{cbegin}, ovvero il \emph{const\_iterator} non ti permetterà di modificare il valore di ciò a cui sta puntando.} \\
\textsf{\small Lo stesso vale per \textbf{end()} e \textbf{cend()}.} \\
\subsubsection{rend()}
\textsf{\small \textbf{rend()} permette di restituire un iteratore inverso (quella r sta per \emph{reverse}). (quindi parte dalla fine e finisce all'inizio)} \\
% -------------------------- SECTION: VIRTUAL ----------------------------------------
\newpage
\section{Virtual}
\subsection{Virtual functions}
\textsf{\small \textbf{Definizione:} Una funzione \textbf{virtuale} è una funzione dichiarata in una classe base che può essere ri-definita (\emph{overridden}) da una classe derivata. Le funzioni \textbf{virtuali} ci assicurano che la corretta versione della funzione venga eseguita.} \\
\textsf{\small Alcune regole per le \textbf{funzioni virtuali}: }
\begin{itemize}
\item \textsf{\small Non possono essere statiche.}
\item \textsf{\small Può essere una \textbf{friend function} di un'altra classe.}
\item \textsf{\small Bisognerebbe accedergli attraverso un puntatore o referenza di un tipo alla classe base per ottenere \emph{runtime polymorphism}.}
\item \textsf{\small Il prototipo della funzione dovrebbe essere lo stesso sia nella classe base sia nella classe derivata.}
\item \textsf{\small Sono sempre definiti nella classe base e ridefiniti nella classe derivata. Non è obbligatorio che la classe derivata ri-definisca la funzione, può anche soltanto utilizzare quella della classe base.}
\item \textsf{\small Una classe può avere un \textbf{virtual destructor}, ma non un \textbf{virtual constructor}.}
\end{itemize}
\begin{lstlisting}
#include <iostream>
class Base {
public:
virtual void print()
{
std::cout << "print in base class" << std::endl;
}
void show()
{
std::cout << "show in base class" << std::endl;
}
};
class Derived : public Base {
public:
void print() override // override non servirebbe, ma aiuta per la manutenzione del codice ed indica che la funzione è stata "overridata".
{
std::cout << "print in derived class" << std::endl;
}
void show()
{
std::cout << "show in derived class" << std::endl;
}
};
int main()
{
Base* bPtr;
Derived d;
bPtr = &d;
// Chiamo la funzione virtuale.
bPtr->print(); // Output: print in derived class
// Chiamo la funzione non virtuale.
bPtr->show(); // Output: show in base class
return 0;
}
\end{lstlisting}
\subsection{Virtual Destructors}
\textsf{\small \textbf{Definizione:} Per rimuovere una classe derivata, la classe base dovrebbe essere definita con un \textbf{distruttore virtuale}. Cancellare una classe derivata usando un puntatore alla classe base senza un distruttore virtuale risulta in un comportamento indefinito (\emph{undefined behaviour}).} \\
\begin{lstlisting}
#include <iostream>
class A {
public:
A()
{
std::cout << "Constructor in base class" << std::endl;
}
virtual ~A()
{
std::cout << "Destructor in base class" << std::endl;
}
};
class B : public A {
public:
B()
{
std::cout << "Constructor in derived class" << std::endl;
}
~B()
{
std::cout << "Destructor in derived class" << std::endl;
}
};
int main()
{
B* bPtr = new B();
A* aPtr = bPtr;
delete aPtr;
// Output:
// Constructor in base class
// Constructor in derived class
// Destructor in derived class
// Destructor in base class
return 0;
}
\end{lstlisting}
\textsf{\small In linea di massima, se si ha una funzione virtuale, allora è da mettere anche il distruttore virtuale.} \break
\subsection{Virtual Inheritance}
\textsf{\small \textbf{Definizione:} L' \textbf{ereditarietà virtuale} è usata per risolvere il problema del \textbf{DDD} (\emph{Dreadful Diamond on Derivation}), ovvero quando una classe deriva molteplici classi che derivano dalla stessa classe.} \\
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/diamond_problem2.png}
\caption{Problema del diamante}
\label{fig:diamond_problem}
\end{figure}
\textsf{\small Come possiamo notare i dati e le funzioni della \textbf{classe A} sono ereditati due volte dalla \textbf{classe D}, una volta per via della \textbf{classe B} e una volta per via della \textbf{classe C}.} \\
\textsf{\small Quando qualsiasi dato o funzione della \textbf{classe A} viene acceduto dalla \textbf{classe D}, nasce dell'ambiguità su quale dato/funzione chiamare. Quella ereditata da \textbf{B} o da \textbf{C}? Questo confonde i compilatori e mostrano errori.}
\textsf{\small Per risolvere questa ambiguità quando la \textbf{classe A} è ereditata sia dalla \textbf{classe B} sia dalla \textbf{classe C}, è dichiarata come \textbf{classe base virtuale} (Fare riferimento all'immagine: \textbf{\ref{fig:diamond_problem}} a \textbf{pag.\pageref{fig:diamond_problem}}).}
\begin{lstlisting}
#include <iostream>
class A {
public:
void show()
{
std::cout << "Show from A" << std::endl;
}
};
class B : public virtual A {
};
class C : public virtual A {
};
class D : public B, public C {
};
int main()
{
D d;
d.show(); // Output: Show from A
}
\end{lstlisting}
\textsf{\small La keyword \textbf{virtual} può essere posta sia prima che dopo \textbf{public}.} \\
%TODO: queste volendo vanno bene anche a 1 di width e height (lasciamole così, così si legge meglio)
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/virtual_functions_recap_terminology_and_concepts1.png}
\caption{Recap Virtual Functions}
\label{fig:virtual_functions_recap_terminology_and_concepts1}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/virtual_functions_recap_terminology_and_concepts2.png}
\caption{Recap Virtual Functions}
\label{fig:virtual_functions_recap_terminology_and_concepts2}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/virtual_functions_implementation.png}
\caption{Virtual Functions Implementazione}
\label{fig:virtual_functions_implementation}
\end{figure}
% -------------------------- SECTION: POLYMORPHISM -----------------------------------
\section{Polimorfismo}
\textsf{\small \textbf{Definizione:} La parola \textbf{polimorfismo} significa \emph{avere molte forme}, questo occorre quando c'è una gerarchia di classi e queste sono correlate attraverso l'ereditarietà.} \\
\textsf{\small Ci sono due tipi principali di polimorfismo: }
\begin{itemize}
\item \textsf{\small \textbf{Compile time Polymorphism} : si ottiene dall'\emph{overloading} di funzioni o di operatori.}
\item \textsf{\small \textbf{Runtime Polymorphism} : si ottiene dall' \emph{overriding} delle funzioni (con la keyword \textbf{virtual}).}
\end{itemize}
\begin{figure}[H]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/polymorphism.png}
\caption{Polimorfismo}
\label{fig:polymorphism}
\end{figure}
% -------------------------- SECTION: OVERLOADING ------------------------------------
\section{Overloading}
\textsf{\small \textbf{Definizione:} L'\textbf{overloading} permette di ridefinire una funzione o un operatore con lo stesso nome e nello stesso scope, ma con una differente implementazione.} \\
\subsection{Function Overloading}
\textsf{\small Si può definire una funzione con lo stesso nome di un'altra purchè abbia argomenti diversi.} \\
\begin{lstlisting}
void func(int x)
{
std::cout << "Valore di x: " << x << std::endl;
}
void func(double x)
{
std::cout << "Valore di x: " << x << std::endl;
}
void func(float x)
{
std::cout << "Valore di x: " << x << std::endl;
}
\end{lstlisting}
\subsection{Operator Overloading}
\textsf{\small Possiamo ridefinire degli operatori per eseguire delle operazioni nel modo che vogliamo noi.} \\
\textsf{\small Utilizziamo la keyword \textbf{operator} ed il simbolo dell'operatore per \emph{overloaddarlo}.} \\
\begin{lstlisting}
class Vec {
public:
Vec(){}
Vec(int x, int y)
{
this->x = x;
this->y = y;
}
Vector operator+(const Vec& v)
{
Vec vec;
vec.x = this->x + v.x;
vec.y = this->y + v.y;
return vec;
}
int getX()
{
return this->x;
}
int getY()
{
return this->y;
}
private:
int x;
int y;
};
int main()
{
Vec v1(3, 2);
Vec v2(1, 0);
Vec v3 = v1 + v2;
std::cout << "v3.x: " << v3.getX() << "; v3.getY(): " << v3.y << std::endl;
// Output: v3.x: 4; v3.y: 2
// perché facciamo la x di v1 che è 3 + la x di v2 che è 1 quindi 4 e
// la y di v1, ovvero 2 + la y di v2, ovvero 0 quindi 2
// quindi v3 ha membri (4,2).
return 0;
}
\end{lstlisting}
\textsf{\small Non tutti gli operatori si possono \emph{overloaddare}.} \\
\textsf{\small Gli operatori che non si possono \emph{overloaddare} sono: \textbf{.} (punto), \textbf{::}, \textbf{?:}(operatore ternario), \textbf{sizeof}.} \\
\subsection{Overloading vs Overriding}
\textsf{\small L'\textbf{overloading} è la creazione di molteplici definizioni di una funzione cambiando la \textbf{signature}: il numero di parametri, la tipologia dei parametri. Il tipo di ritorno non gioca alcun ruolo.} \\
\textsf{\small Può essere fatta sia nelle classi basi che in quelle derivate.} \break
\textsf{\small L'\textbf{overriding} è la ridefinizione di una funzione di una classe base in una classe derivata con la stessa \textbf{signature}, stesso tipo di ritorno e parametri.} \\
\textsf{\small Può essere fatta solo nelle classi derivate.} \break
\textsf{\small Differenza tra \textbf{function overloading} e \textbf{function overriding}: } \break
\begin{tabular}{|c|c|} %TODO: questo è da riguardare, perché la fonte forse ha fatto degli errori.
\hline
\textbf{Overloading} & \textbf{Overriding} \\
\hline
\textsf{\small Nessuna keyword è usata.} & \textsf{\small Keyword \textbf{override}.} \\
\hline
\textsf{\small Il prototipo cambia } & \textsf{\small Il prototipo non cambia.} \\
\textsf{\small in base ai parametri.} & \textsf{\small } \\
\hline
\textsf{\small Occorre durante compile time.} & \textsf{\small Occorre durante runtime.} \\
\hline
\textsf{\small I costruttori possono } & \textsf{\small } \\
\textsf{\small essere "overloaddati".} & \textsf{\small } \\
\hline
\textsf{\small I distruttori non } & \textsf{\small I distruttori } \\
\textsf{\small possono essere "overloaddati".} & \textsf{\small possono essere "overridati".} \\
\hline
\textsf{\small } & \textsf{\small Le funzioni virtuali } \\
\textsf{\small } & \textsf{\small non possono essere "overridate".} \\
\hline
\textsf{\small Può essere usato per ottenere } & \textsf{\small Overriding è anche conosciuto come } \\
\textsf{\small \emph{early binding}.} & \textsf{\small \emph{late binding}.} \\
\hline
\textsf{\small La funzione chiamata viene } & \textsf{\small La funzione overriden} \\
\textsf{\small determinata dal numero} & \textsf{\small è preceduta} \\
\textsf{\small di parametri.} & \textsf{\small dalla keyword virtual nella classe base.} \\
\hline
\textsf{\small Le funzioni verrebbero} & \textsf{\small } \\
\textsf{\small ridefinite} & \textsf{\small } \\
\textsf{\small con lo stesso nome, ma} & \textsf{\small } \\
\textsf{\small differente numero o tipo} & \textsf{\small } \\
\textsf{\small di parametri.} & \textsf{\small } \\
\hline
\textsf{\small } & \textsf{\small L'indirizzo dell'oggetto} \\
\textsf{\small } & \textsf{\small della classe è assegnato al} \\
\textsf{\small } & \textsf{\small puntatore la cui funzione} \\
\textsf{\small } & \textsf{\small è chiamata dal puntatore.} \\
\hline
\textsf{\small } & \textsf{\small Quando la funzione è definita viene preceduta} \\
\textsf{\small } & \textsf{\small dalla keyword virtual nel main.} \\
%\textsf{\small } & \textsf{\small La stessa funzione è ridefinita } \\
%\textsf{\small } & \textsf{\small nella classe derivata usando} \\
%\textsf{\small } & \textsf{\small la keyword \textbf{out}.} \\
%\textsf{\small } & \textsf{\small } \\
\hline
\end{tabular}
% -------------------------- SECTION: TIPI DI CAST -----------------------------------
\label{cast_types}
\newpage
\section{Tipi di Casts}
\textsf{\small \textbf{Definizione:} Il \textbf{casting} è un'operazione che permette la conversione di un valore in un altro. In C++ ci sono diversi tipi di casting: } \\
\subsection{static\_cast<>}
\begin{itemize}
\item \textsf{\small \textbf{static\_cast<> :} Quello che fa è un cast implicito tra tipi (come int a float, o puntatore a void*) e può anche chiamare funzioni esplicite per la conversione. }
\end{itemize}
\begin{lstlisting}
float f = 3.69;
int x = static_cast<int>(f);
std::cout << "x: " << x << std::endl; // Output: x: 3
\end{lstlisting}
\subsection{const\_cast<>}
\begin{itemize}
\item \textsf{\small \textbf{const\_cast<> :} Serve per aggiungere o rimuovere il \textbf{const} ad una variabile. Se la variabile che stiamo cercando di modificare era già const allora questo produce un valore indefinito. Se lo si usa per qualcosa che non era dichiarato come const allora è safe (sicuro farlo, non ci saranno problemi). }
\end{itemize}
\begin{lstlisting}
#include <iostream>
void print( char* str)
{
std::cout << str << '\n';
}
int main()
{
const char* c = "testo";
// Ci serve per poter passare un puntatore a char const ad una funzione che prende un puntatore a char senza const.
print(const_cast<char*>(c)); // Output: testo
return 0;
}
\end{lstlisting}
\subsection{dynamic\_cast<>}
\begin{itemize}
\item \textsf{\small \textbf{dynamic\_cast<> :} Serve esclusivamente per i casts riguardanti il polimorfismo. Puoi castare un puntatore o una reference a qualsiasi altro tipo di classe. Non solo si può fare un casting verso il basso, ma anche verso l'alto e a lato. Il dynamic\_cast cercherà di ritorna l'oggetto desiderato se possibile, altrimenti ritornerà \textbf{nullptr} in caso di un puntatore e \textbf{std::bad\_cast} nel caso di una reference.}
\item \textsf{\small Ha delle limitazioni. Non funzionerà nel caso in cui diversi oggetti ereditano tutti dallo stessa classe. (il famoso problema del \emph{dreaded diamond}.) e non stai usando l'ereditarietà \textbf{virtual}.}
\item \textsf{\small Inoltre può soltanto funzionare con l'ereditarietà pubblica, fallirà con l'ereditarietà \textbf{protected} o \textbf{private}. Comunque questi tipi di ereditarietà sono rare.}
\end{itemize}
\begin{lstlisting}
// C++ programma per dimostrare che se non c'è
// alcuna funzione virtuale nella Base classe.
#include <iostream>
// Base class declaration
class Base {
void print()
{
std::cout << "Base" << std::endl;
}
};
// Derived Class 1 declaration
class Derived1 : public Base {
void print()
{
std::cout << "Derived1" << std::endl;
}
};
// Derived class 2 declaration
class Derived2 : public Base {
void print()
{
std::cout << "Derived2" << std::endl;
}
};
// Driver Code
int main()
{
Derived1 d1;
// Base class pointer hold Derived1
// class object
Base* bp = dynamic_cast<Base*>(&d1);
// Dynamic casting
Derived2* dp2 = dynamic_cast<Derived2*>(bp);
if (dp2 == nullptr)
std::cout << "null" << std::endl;
// Output: null, in realtà errore.
return 0;
}
\end{lstlisting}
\subsection{reinterpret\_cast<>}
\begin{itemize}
\item \textsf{\small \textbf{reinterpret\_cast<> :} È quello più pericoloso di tutti e quindi bisogna utilizzarlo con moderazione. Trasforma un tipo direttamente in un altro come cast da un puntatore ad un altro o memorizzare un puntatore in un int, ecc.}
\item \textsf{\small L'unica cosa garantita con questo tipo di cast è che se torni indietro al tipo originale riotterrai lo stesso valore (non succederà se il tipo era più piccolo del tipo originale.)}
\end{itemize}
\begin{lstlisting}
class A {
public:
int x;
};
class B {
public:
int x;
};
A *a = new A;
B *b = reinterpret_cast<*B>(a);
a->x = 5;
std::cout << "b: " << b->x << std::endl; // Output: b: 5
std::cout << "a: " << a->x << std::endl; // Output: a: 5
\end{lstlisting}
\subsection{C-style \& function-style cast o Regular Cast}
\begin{itemize}
\item \textsf{\small Questo tipo di cast chiamato \textbf{Regular Cast} o \textbf{C-style cast} (derivando dal C ovviamente) è molto più potente degli altri tipi di cast, ma allo stesso tempo molto meno sicuro.}
\item \textsf{\small Ignorano i controlli d'accesso quando si esegue uno static\_cast.}
\item \textsf{\small Permette di fare un cast sicuro ad una classe privata, mentre il suo "equivalente" static\_cast darebbe un errore a tempo di compilazione (compile-time).}
\end{itemize}
\begin{lstlisting}
double d = 9.87;
int x;
x = (int)d;
std::cout << "x: " << x std::endl; // Output: x: 9
\end{lstlisting}
\subsection{Ricapitolando}
\begin{tabular}{|c|c|}
\hline
\textbf{Cast} & \textbf{Definizione} \\
\hline
\textbf{dynamic\_cast} & \textsf{\small per convertire puntatori/references } \\
\textbf{} & \textsf{\small in una gerarchia di ereditarietà.} \\
\hline
\textbf{static\_cast} & \textsf{\small per le conversioni di tipi ordinari.} \\
\hline
\textbf{reinterpret\_cast} & \textsf{\small per reinterpretare bit patterns di basso livello. } \\
\textbf{} & \textsf{\small Usare con cauzione.} \\
\hline
\textbf{const\_cast} & \textsf{\small per aggiungere/rimuovere \textbf{const} al cast.} \\
\hline
\end{tabular}
\begin{figure}[ht]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/typecasting.png}
\caption{Typecasting}
\label{fig:typecasting}
\end{figure}
\begin{figure}[ht]
\centering
\includegraphics[width=1\textwidth, height=1\textheight, keepaspectratio]{./imgs/cast_types_recap_static_dynamic_reinterpret_const_c-style2.png}
\caption{Recap Cast Types}
\label{fig:cast_types_recap_static_dynamic_reinterpret_const_c-style2}
\end{figure}
% -------------------------- SECTION: LAMBDAS ----------------------------------------
%TODO: potrei mettere le lambbdas subito dopo gli iteratori.
\section{Lambdas}
\textsf{\small \textbf{Definizione:} Dal C++11 sono presenti le \textbf{lambdas} che permettono di creare \textbf{funzioni anonime}.} \\
\textsf{\small Servono per creare delle funzioni, dei piccoli frammenti di codice che non hanno bisogno di un nome e non verranno riutilizzati. } \\ % funzioni inline
\textsf{\small Sono una parte centrale della \textbf{programmazione funzionale}.} \\
\textsf{\small Questa è la struttura di una tipica espressione \textbf{lambda} :} \\
\begin{lstlisting}
[ clausola di cattura ] ( lista di parametri che è opzionale) -> tipoDiRitorno
{
// Definizione della lambda.
}
\end{lstlisting}
\textsf{\small Se nella clausola della cattura è presente un \textbf{=} (uguale), vuol dire che la lambda può accedere a qualsiasi variabile, se c'è un \textbf{\&} vuol dire che stiamo accedendo alle variabili per reference, se la clausola [] è vuota allora può accedere soltanto alle variabili locali, altrimenti lì saranno presenti i nomi delle variabili che si vogliono utilizzare ("catturate" o per valore o per reference).} \\ %TODO: forse si potrebbe rimuovere questa parte e lasciare solo la tabella.
\begin{tabular}{|c|c|}
\hline
\textbf{Cattura} & \textbf{Definizione} \\
\hline
\textsf{\small []} & \textsf{\small accedere solo alla variabili locali} \\
\hline
\textsf{\small [=]} & \textsf{\small accedere a tutte le variabili per valore.} \\
\hline
\textsf{\small [\&]} & \textsf{\small accedere a tutte le variabili per reference.} \\
\hline
\textsf{\small [nomeVariabile1, \&nomeVariabile2]} & \textsf{\small "cattura" nomeVariabile1 per valore } \\
\textsf{\small } & \textsf{\small e nomeVariabile2 per referenza.} \\
\hline
\end{tabular} \\
\begin{lstlisting}
#include <iostream>
#include <vector>
std::vector<int> v1 = { 5, 8, 9, 1, 7};
std::vector<int> v2 = {12, 36, 27, 92};
// Lambda.
auto pushinto = [&](int m)
{
v1.push_back(m);
v2.push_back(m);
}; // Da notare il ; alla fine.
// Pusha in entrambi v1 e v2 il numero 24
pushinto(24);
// Lambda, accediamo a v1 per valore (quindi ne facciamo una copia).
[v1]()
{
for(auto p = v1.begin(); p != v1.end(); p++)
{
std::cout << *p << std::endl;
}
};
int n = 7;
// trova il primo numero maggiore di n.
// [n] significa che stiamo accedendo e possiamo soltanto accedere ad n (per valore, ovvero una copia di essa).
std::vector<int>:: iterator p = std::find_if(v1.begin(), v1.end(), [n](int i)
{
return i > n;
});
std::cout << "Il primo numero maggiore di n e\': " << *p << std::endl; // Output: Il primo numero maggiore di n e\': 8
// Qui [=] vuol dire che possiamo accedere a tutte le variabili.
int countN = std::count_if(v1.begin(), v1.end(), [=](int a)
{
return a >= n;
});
std::cout << "Il numero di elementi piu' grandi o uguali ad n sono: " << countN << std::endl; // Output: Il numero di elementi più grandi o uguali ad n sono: 4 (perchè abbiamo inserito anche il 24 nell'operazione precedente).
\end{lstlisting}
%TODO: poi trattare anche dei functors.
\subsection{mutable}
\textsf{\small \textbf{Definizione: } La parola chiave \textbf{mutable} serve per modificare certi dati membri di una classe o struttura attraverso una funzione costante o una lambda (quando le variabili sono catturati per valore) anche se non vuoi modificare gli altri membri.} \\
\begin{lstlisting}
#include <iostream>
int main()
{
int a = 11;
auto func = [a]() mutable -> int { ++a; std::cout << a << '\n'; return a; };
func(); //Output: 12
return 0;
}
\end{lstlisting}
%TODO: magari approfondire o mostrare altri esempi.
% -------------------------- SECTION: MEMORIA DINAMICA -------------------------------
\newpage
\section{Memoria dinamica}
\textsf{\small \textbf{Definizione: } Riguarda l'allocazione di memoria allocata manualmente da parte del programmatore. La memoria allocata dinamicamente è allocata nell' \textbf{Heap} mentre le variabili locali e la memoria non statica viene allocata nello \textbf{Stack}.}
\begin{itemize}
\item \textsf{\small \textbf{Heap} : memoria dinamica.}
\item \textsf{\small \textbf{Stack} : variabili locali e non-statiche.}
\end{itemize}
\begin{figure}[H]
\centering
\includegraphics[width=.9\textwidth, height=.9\textheight, keepaspectratio]{./imgs/allocate_and_deallocate_memory2.png}
\caption{Memoria}
\label{fig:allocate_and_deallocate_memory}
\end{figure}
\subsection{Memoria Dinamica in C}
\textsf{\small In C per l'allocazione dinamica della memoria usufruivamo di 4 diverse funzioni: \textbf{malloc()} (per allocare), \textbf{calloc() (alloca e setta la memoria a zero a differenza della malloc)}, \textbf{realloc()} (per riallocare), \textbf{free()} (per liberare la memoria).} \\
\textsf{\small Tutte questi funzioni del C, esistono anche nel C++, ma questo ha un suo modo per allocare memoria dinamicamente.} \break
\subsection{new e delete}
\subsubsection{new}
\textsf{\small \textbf{Definizione: } L'operatore \textbf{new} denota una richiesta di allocazione di memoria nello spazio libero. Se sufficiente memoria è disponibile, l'operatore inizializza la memoria e restituisce l'indirizzo della nuova memoria allocata ed inizializzata al puntatore.} \\
\begin{lstlisting}
// Esempio 1
int *ptr = nullptr;
ptr = new int;
// Esempio 2
double *dPtr = new double;
// Esempio 3
int *p = new int(22);
// Esempio 4
int *pArray = new int[12];
\end{lstlisting}
\subsubsection{array normali vs array con la new}
\textsf{\small L'unica differenza è che gli array normali vengono deallocati dal compilatore, mentre quelli creati con la new devono essere deallocati dal programmatore.} \break
\subsubsection{delete}