// ex12_3_1.cpp #include <iostream.h> class A { public: A () { cout << "A::A()\n"; } A& operator=(A&) { cout << "A::operator=()\n"; } ~A () { cout << "A::~A()\n"; } }; class B : public A { }; void main() { B b, c; b = c; }
output:
A::A() A::A() A::operator=() A::~A() A::~A()
Vediamo ora come costruire da noi costruttori, distruttore e operatore di assegnamento, tramite un semplice esempio. La prima classe che definiamo è la Array
, sulla quale non ci soffermeremo affatto, avendo ormai visto sotto ogni possibile sfumatura luminosa le classi array.
class Array { public: Array (unsigned n) { cout << "Array::Array()\n"; nelem = n; array = new int[nelem]; for (int i = 0; i < nelem; i++) array[i] = 0; } Array (const Array& a) { cout << "Array::Array(const Array&)\n"; nelem = a.nelem; array = new int[nelem]; for (int i = 0; i < nelem; i++) array[i] = a.array[i]; } const Array& operator= (const Array& a) { if (&a != this) { cout << "Array::operator= (const Array&)\n"; if (nelem != a.nelem) { nelem = a.nelem; delete[] array; array = new int[nelem]; } for (int i = 0; i < nelem; i++) array[i] = a.array[i]; } } int& operator[] (int i) { return array[i]; } int somma() { int s = 0; for (int i = 0; i < nelem; i++) s+= array[i]; return s; } ~Array () { cout << "Array::~Array()\n"; delete[] array; } private: int* array; unsigned nelem; };
Si suppone ora di avere bisogno di un Array
, il quale però abbia anche un nome immagazzinato in un char*; dobbiamo effettuare allora il subtyping della classe Array
aggiungendo i campi necessari al nostro scopo. Siccome dobbiamo allocare un char* nello heap, dovremo programmare anche i costruttori, il distruttore e l'operatore di assegnamento.
class ArrayN : public Array { public: ArrayN (unsigned n, char* s) : Array(n) { cout << "ArrayN::ArrayN()\n"; nome = new char[strlen(s)]; strcpy (nome, s); } ArrayN (const ArrayN& a) : Array(a) { cout << "ArrayN::ArrayN(const ArrayN&)\n"; nome = new char[strlen(a.nome)]; strcpy (nome, a.nome); } const ArrayN& operator= (const ArrayN& a) { cout << "ArrayN::operator=(const ArrayN&)\n"; Array::operator= (a); if (strlen(nome) != strlen(a.nome)) { delete[] nome; nome = new char[strlen(a.nome)]; strcpy (nome, a.nome); } return *this; } char* getNome () const { return nome; } void setNome (char* s) { delete[] nome; nome = new char[strlen(s)]; strcpy (nome, s); } operator char* () const { return getNome(); } ~ArrayN () { cout << "ArrayN::~ArrayN()\n"; delete[] nome; } private: char* nome; };
Si faccia molta attenzione alla sintassi utilizzata per chiamare il costruttore di copia e l'operatore di assegnamento della classe base:
ArrayN (const ArrayN& a) : Array(a) { /*...*/ } |
a
non è del tipo della classe base bensì di quella derivata. Per l'operator= la sintassi è:
Array::operator= (a); |
a
è di tipo ArrayN
mentre l'operatore di assegnamento della classe base prevede come argomento un oggetto di tipo Array
. Miracoli del C++.
Un semplice esempio che testi le classi or ora programmate è il seguente:
// ex12_3_2.cpp #include <string.h> #include <iostream.h> /* definizioni di Array e ArrayN */ void main() { ArrayN a(5, "pippo"); for (int i = 0; i < 5; i++) a[i] = i+1; ArrayN b(a); b.somma(); // 15 b.setNome ("topolino"); ArrayN c(a); c = b; c.getNome(); // topolino }
output:
Array::Array() | a | |
ArrayN::ArrayN() | a | |
Array::Array(const Array&) | b | |
ArrayN::ArrayN(const ArrayN&) | b | |
Array::Array(const Array&) | c | |
ArrayN::ArrayN(const ArrayN&) | c | |
ArrayN::operator=(const ArrayN&) | c | |
Array::operator= (const Array&) | c | |
ArrayN:: ArrayN() | c | |
Array:: Array() | c | |
ArrayN:: ArrayN() | b | |
Array:: Array() | b | |
ArrayN:: ArrayN() | a | |
Array:: Array() | a |