Allora cerco di spiegarmi un po' meglio. Nella classe astratta FormaGeometrica ci sono semplicemente funzioni virtuali pure e due funzioni di get. Non è inutile includere il file iostream?
Il file corretto FormaGeometrica.h è questo?
#ifndef FORMAGEOMETRICA_H
#define FORMAGEOMETRICA_H
class FormaGeometrica // Classe astratta
{
public:
virtual double area() const { return 0.0; }
virtual double volume() const { return 0.0; }
// Funzioni virtuali pure che subiranno ridefinizioni nelle
// classi derivate
virtual void StampaNomeFigura() const = 0;
virtual void StampaParametri() const = 0;
};
#endif
Passiamo ora al file Punto.h che è una classe derivata da FormaGeometrica. In questo header c'è la funzione virtuale StampaNomeFigura che è definita inline. Questa funzione usa cout per lo stream di output giusto? Quindi in questo file oltre a quello che ho scritto di codice, ossia
#ifndef PUNTO_H
#define PUNTO_H
#include "FormaGeometrica.h"
....
dovrei aggiungere anche
#include <iostream>
using std::cout;
? Cioè il codice corretto è questo?
#ifndef PUNTO_H
#define PUNTO_H
#include "FormaGeometrica.h"
#include <iostream>
using std::cout;
class Punto : public FormaGeometrica
{
public:
Punto (int a = 0, int b = 0); // costruttore di default
void setPunto (int a, int b);
int getX() const { return x; }
int getY() const { return y; }
virtual void StampaNomeFigura() const { cout << "Punto: "; }
virtual void StampaParametri() const;
private:
int x, y;
};
#endif
Passiamo al file Punto.cpp, l'implementazione. Anche qui uso cout devo scrivere anche qui #include <iostream> using std::cout; ? Il codice corretto è questo?
#include <iostream>
using std::cout;
#include "Punto.h"
Punto::Punto (int a, int b) { setPunto (a, b); }
void Punto::setPunto (int a, int b)
{
x = a;
y = b;
}
void Punto::StampaParametri() const
{
cout << "(" << x << ", " << y << ")";
}
A questo punto senza che dica le stesse cose anche per le altre classi incollo il codice che secondo me è corretto. La domanda finale qual è? Bisogna trattare e includere in tutti i file della gerarchia le librerie necessarie a seconda degli oggetti che si usano oppure c'è una qualche forma di ereditarietà anche con le librerie? Cioè se io nella superclasse in questo caso FormaGeometrica.h includo la libreria iostream con using std::cout; questa viene "inclusa" anche nelle classi derivate che ad esempio utilizzano cout? O bisogna come ho ragionato io specificare tutte le librerie necessarie in ogni singolo file che si tratti di un file .h o .cpp? Per esempio se oltre a cout nel file Punto.h c'era anche un manipolatore di stream come setiosflags dovevo scrivere #include <iomanip> using std::setiosflags;? Tratto i file singolarmente o no? Incollo il codice:
// File punto.cpp
#include <iostream>
using std::cout;
#include "Punto.h"
Punto::Punto (int a, int b) { setPunto (a, b); }
void Punto::setPunto (int a, int b)
{
x = a;
y = b;
}
void Punto::StampaParametri() const
{
cout << "(" << x << ", " << y << ")";
}
// File cerchio.h
#ifndef CERCHIO_H
#define CERCHIO_H
#include "Punto.h"
#include <iostream>
using std::cout;
class Cerchio : public Punto
{
public:
Cerchio (int x = 0, int y = 0, double r = 0.0);
void setRaggio (double r);
double getRaggio() const { return raggio; }
virtual double area() const;
virtual void StampaNomeFigura() { cout << "Cerchio: "; }
virtual void StampaParametri() const;
private:
double raggio;
};
#endif
// File cerchio.cpp
#include <iostream>
using std::cout;
#include "Cerchio.h"
Cerchio::Cerchio (int x, int y, double r) : Punto(x, y) { setRaggio(r); }
void Cerchio::setRaggio (double r)
{
raggio = r > 0 ? r : 0; // Se il raggio è maggiore di 0 dà r altrimenti 0
}
double Cerchio::area() const
{
return (3.14159 * raggio * raggio);
}
void Cerchio::StampaParametri() const
{
Punto::StampaParametri();
cout << "; Raggio = " << raggio;
}
// File Cilindro.h
#ifndef CILINDRO_H
#define CILINDRO_H
#include "Cerchio.h"
#include <iostream>
using std::cout;
class Cilindro : public Cerchio
{
public:
Cilindro (int x = 0, int y = 0, double r = 0.0, double h = 0.0);
void setAltezza (double h);
virtual double area() const;
virtual double volume() const;
virtual void StampaNomeFigura() const { cout << "Cilindro: "; }
virtual void StampaParametri() const;
private:
double altezza;
};
#endif
// File cilindro.cpp
#include <iostream>
using std::cout;
#include "Cilindro.h"
Cilindro::Cilindro (int x, int y, double r, double h) : Cerchio (x, y, r)
{ setAltezza(h); }
void Cilindro::setAltezza (double h)
{
altezza = h > 0 ? h : 0; // Se l'altezza è maggiore di 0 dà h altrimento 0
}
/* La formula dell'area di un cilindro è 2*pi*r^2 + 2*pi*r*h: Cerchio::area()
restituisce pi*r^2 richiamando il metodo area() della classe Cerchio. getRaggio()
invece mi restituisce il raggio. */
double Cilindro::area() const
{
return (2 * Cerchio::area()) + (2 * 3.14159 * getRaggio() * altezza);
}
// Il volume di un cilindro è pi*r^2*h
double Cilindro::volume() const
{
return Cerchio::area() * altezza;
}
void Cilindro::StampaParametri() const
{
Cerchio::StampaParametri();
cout << "; Altezza = " << altezza;
}
// File main .cpp
#include <iomanip>
using std::setiosflags;
using std::setprecision;
#include <cstdlib>
using std::system;
#include <iostream>
using std::cout;
using std::fixed;
using std::showpoint;
using std::ios;
using std::endl;
#include "Cilindro.h"
void Polimorfismo_puntatore (const FormaGeometrica* Punt); // Passo un punt. alla classe base
void Polimorfismo_riferimento (const FormaGeometrica& Rif);// Passo un rif. alla classe base
int main ()
{
// Imposto a 2 il numero di cifre da visualizzare dopo il punto decimale
cout << setiosflags(ios::fixed | ios::showpoint) << setprecision(2);
Punto pun(7, 11); // oggetto punto di coordinate x = 7, y = 11
Cerchio cer(22, 8, 3.5); // oggetto cerchio con x = 22, y = 8, raggio = 3.5
Cilindro cil (10, 10, 3.3, 10); // cilindro x = 10, y = 10, raggio = 3.3, altezza = 10
pun.StampaNomeFigura(); // binding statico
pun.StampaParametri(); // binding statico
cout << "\n";
cer.StampaNomeFigura(); // binding statico
cer.StampaParametri(); // binding statico
cout << "\n";
cil.StampaNomeFigura(); // binding statico
cil.StampaParametri(); // binding statico
cout << "\n\n";
// Array di puntatori della classe base inizializzato ai tre oggetti derivati
FormaGeometrica *ArrayDiFigure[3] = {&pun, &cer, &cil};
cout << "Binding dinamico attraverso un puntatore" << endl << endl;
/* Ciclo che attraversa ArrayDiFigure e chiama Polimorfismo_puntatore
per visualizzare il nome, gli attributi, l'area e il volume di ogni
oggetto utilizzando il binding dinamico */
for (int i = 0; i < 3; i++)
Polimorfismo_puntatore(ArrayDiFigure[i]);
cout << "Binding dinamico attraverso un riferimento" << endl << endl;
// Stessa cosa precedente usando stavolta un riferimento alla classe base
for (int i = 0; i < 3; i++)
Polimorfismo_riferimento(*ArrayDiFigure[i]);
system ("pause");
return 0;
}
void Polimorfismo_puntatore (const FormaGeometrica* Punt)
{
Punt->StampaNomeFigura();
Punt->StampaParametri();
cout << "\nArea = " << Punt->area()
<< "\nVolume = " << Punt->volume() << "\n\n";
}
void Polimorfismo_riferimento (const FormaGeometrica& Rif)
{
Rif.StampaNomeFigura();
Rif.StampaParametri();
cout << "\nArea = " << Rif.area()
<< "\nVolume = " << Rif.volume() << "\n\n";
}
Ultima domanda. Mi dicesti che nei file che non siano il main meglio usare la forma using std::...
ma nel main posso usare using namespace std? Che tecnica mi consigli. Comunque con le modifiche che ho scritto il programma parte benissimo. Però chiariscimi i concetti di cui sopra e nel caso postami il tuo codice sugli include nei vari file se non ti chiedo troppo. Grazie