Lezione 5

This commit is contained in:
Alessandro Ferro 2021-03-26 11:01:56 +01:00
parent a0fc2e6e6d
commit bfc9b6ecd3
8 changed files with 355 additions and 1 deletions

BIN
teoria/classi/a.out Executable file

Binary file not shown.

View File

@ -0,0 +1,51 @@
#include<iostream>
using namespace std;
class A{
public:
int x;
A(){
cout<<"Sono nel costruttore di A"<<endl;
x = x+1;
}
A(const A& a){
cout<<"Sono nel costruttore di copia di A"<<endl;
}
};
class B:public A{
public:
B(){
cout<<"Sono nel costruttore di B"<<endl;
x+=100;
}
B(const B& b){
cout<<"Sono nel costruttore di copia di B"<<endl;
}
};
class C:public B{
public:
C(){
cout<<"Sono nel costruttore di C"<<endl;
x+=1000;
}
C(const C& c){
cout<<"Sono nel costruttore di copia di C"<<endl;
}
};
int main(){
/*
Sono nel costruttore di A
Sono nel costruttore di B
Sono nel costruttore di C
*/
C obj;
cout<<endl;
/*
Sono nel costruttore di A
Sono nel costruttore di B
Sono nel costruttore DI COPIA di C
*/
C obj2(obj);
return 0;
}

View File

@ -0,0 +1,66 @@
#include<iostream>
using namespace std;
void problema();
void soluzione();
int main(){
//problema();
soluzione();
return 0;
}
void problema(){
class A{
public:
int* v = new int[10];
~A(){
cout<<"Richiamato distuttore di A"<<endl;
delete[] v;
}
};
class B: public A{
public:
char* s = new char[20];
~B(){
cout<<"Richiamato distruttore di B"<<endl;
delete[] s;
}
};
A* ptr = new B(); //dato che B è anche un tipo A, questo può essere fatto.
delete ptr; // "Richiamato distruttore di A"
/*
Creo un oggetto B (quindi che contiene anche A) e lo assegno a un puntatore
a oggetto A.
Se poi faccio "delete ptr" il compilatore va a richiamare il distruttore di A
e non anche quello di B. Quindi l'array di char "s" rimarrà in memoria almeno
fino al termine del programma.
*/
}
void soluzione(){
class A{
public:
int* v = new int[10];
/*
Virtual functions ensure that the correct function is called for an object,
regardless of the type of reference (or pointer) used for function call.
https://www.geeksforgeeks.org/virtual-function-cpp/
*/
virtual ~A(){ // metodo virtuale. Deve essere sempre fatto così sui distruttori.
cout<<"Richiamato distuttore di A"<<endl;
delete[] v;
}
};
class B: public A{
public:
char* s = new char[20];
~B(){
cout<<"Richiamato distruttore di B"<<endl;
delete[] s;
}
};
A* ptr = new B(); //dato che B è anche un tipo A, questo può essere fatto.
delete ptr; // "Richiamato distruttore di B Richiamato distuttore di A"
}

View File

@ -10,5 +10,41 @@
= 0: pure virtual. A questo livello l'implementazione di questo metodo non esiste = 0: pure virtual. A questo livello l'implementazione di questo metodo non esiste
= default: ammesso solo per cost. e dist. che dice di creare quelli di default = default: ammesso solo per cost. e dist. che dice di creare quelli di default
=delete: elimina un metodo precedentemente scritto nella gerarchia =delete: elimina un metodo precedentemente scritto nella gerarchia
*/ */
/*
Il corpo di una funzione può essere messo anche fuori dalla classe:
*/
#include<iostream>
class ClassName{
private:
int y = 5;
public:
int x = 3;
int aggiungiX(int); // dichiarazione funzione
int aggiungiY(int); // dichiarazione funzione
friend int aggiungiY(int); // dichiarazione friendship
};
/*
NB: in questo caso x deve essere dichiarata pubblica. Se fosse stato un metodo
all'interno della classe allora avrebbe potuto avere accesso anche se x
fosse stata privata
*/
int ClassName::aggiungiX(int parametro){
x+=parametro;
}
/*
Oppure si può dichiarare la friendship per accedere a variabili private/protette
*/
int ClassName::aggiungiY(int parametro){
y+=parametro;
std::cout<<y<<std::endl;
}
int main(){
ClassName obj;
obj.aggiungiX(7);
obj.aggiungiY(9);
std::cout<<obj.x<<std::endl;
return 0;
}

View File

@ -0,0 +1,77 @@
#include<iostream>
using namespace std;
/*
ereditarietà a diamante:
A <-- B
A <-- C
B <-- D
C <-- D
*/
class A{
public:
int a;
A(){
cout<<"A created"<<endl;
}
~A(){
cout<<"A destroyed"<<endl;
}
};
class B : A{
public:
int b;
B(){
cout<<"B created"<<endl;
}
~B(){
cout<<"B destroyed"<<endl;
}
};
class C : A{
public:
int c;
C(){
cout<<"C created"<<endl;
}
~C(){
cout<<"C destroyed"<<endl;
}
};
class D : B,C{
public:
int d;
D(){
cout<<"D created"<<endl;
}
~D(){
cout<<"D destroyed"<<endl;
}
};
int main(){
/*
Ogni oggetto deve avere all'interno gli oggetti ereditati. Quindi stampa:
A created (per creare D mi serve prima B. Per creare B mi serve prima A)
B created (creato A, posso creare B)
A created (per creare D mi serve prima C. Per creare C mi serve prima A)
C created (creato A, posso creare C)
D created (creato B che contiene A e creato C che contiene A, posso creare D)
*/
D obj;
cout<<endl;
return 0;
/*
La distruzione viene effettuata al contrario
D destroyed
C destroyed
A destroyed
B destroyed
A destroyed
*/
}

View File

@ -0,0 +1,81 @@
#include<iostream>
using namespace std;
/*
ereditarietà a diamante:
A <-- B
A <-- C
B <-- D
C <-- D
*/
void nonVirtualInheritance();
void virtualInheritance();
int main(){
//nonVirtualInheritance();
virtualInheritance();
return 0;
}
void nonVirtualInheritance(){
class A{
public:
int size = 7;
};
class B : public A{
public:
int b;
};
class C : public A{
public:
int c;
};
class D : public B, public C{
public:
int d;
};
/*
Adesso B ha una copia di A, C ha una copia di A, D ha una copia di B e una
copia di C. Implica che D ha due copie di A.
Se provo a stampare size, cosa succede?
*/
D obj;
//cout<<obj.size<<endl; //request for member size is ambiguous
cout<<obj.B::size<<endl;
cout<<obj.C::size<<endl;
}
void virtualInheritance(){
class A{
public:
int size = 7;
};
class B : virtual public A{
public:
int b;
};
class C :virtual public A{
public:
int c;
};
class D : public B, public C{
public:
int d;
};
D obj;
cout<<obj.size; // adesso posso stampare tranquillamente size
/*
Questo è possibile grazie al fatto che B e C ereditano A in modo virtuale,
ovverosia, c'è solo un'istanza A condivisa tra B e C.
https://www.cprogramming.com/tutorial/virtual_inheritance.html
*/
}

View File

@ -0,0 +1,43 @@
#include<iostream>
using namespace std;
class A{
private:
int a = 1;
protected:
int b = 2;
public:
int c = 3;
int sameVariable = 4;
};
class B : A{
public:
int sameVariable = 9;
void test(){
//cout<<a<<endl; // errore, "a" è privata
cout<<b<<endl; // 2
cout<<c<<endl; // 3
cout<<sameVariable<<endl; // 9
}
};
int main(){
B b;
b.test();
//cout<<b.a<<endl; //NO
//cout<<b.b<<endl; //NO
/*
Benché A::c sia pubblica, non posso accedergli da qua perché di default
l'ereditarietà viene fatta in modo privato.
Se avessi scritto class B:public A allora avrei potuto stampare.
*/
//cout<<b.c<<endl; //NO
cout<<b.sameVariable<<endl; // 9
/*
Se l'ereditarietà fosse stata pubblica (B: public A) avrei potuto scrivere
cout<<b.A::sameVariable<<endl;
per eccedere a "sameVariable" di A
*/
}

Binary file not shown.