Classi Poligono, Rettangolo e Quadrato

Di seguito intestazione e implementazione delle classi scritte durante la lezione del 7 maggio 2013. In fondo anche un esempio d’uso.

1
2
3
4
5
6
7
8
9
10
#ifndef POLIGONO_H
#define POLIGONO_H
 
class Poligono {
public:
    virtual double area() const = 0;
    virtual double perimetro() const = 0;
};
 
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef RETTANGOLO_H
#define RETTANGOLO_H
 
#include "Poligono.h"
 
class Rettangolo : public Poligono {
public:
    Rettangolo(double base = 1, double altezza = 1);
 
    double getBase() const { return base; }
    double getAltezza() const { return altezza; }
 
    virtual void setBase(double val);
    virtual void setAltezza(double val);
 
    virtual double perimetro() const;
    virtual double area() const;
 
private:
    double base;
    double altezza;
};
 
#endif
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
#include "Rettangolo.h"
 
#include <cassert>
 
Rettangolo::Rettangolo(double initBase, double initAltezza) {
    setBase(initBase);
    setAltezza(initAltezza);
}
 
void Rettangolo::setBase(double val) {
    assert(val > 0);
    base = val;
}
 
void Rettangolo::setAltezza(double val) {
    assert(val > 0);
    altezza = val;
}
 
double Rettangolo::perimetro() const {
    return (base + altezza) * 2;
}
 
double Rettangolo::area() const {
    return base * altezza;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef QUADRATO_H
#define QUADRATO_H
 
#include "Rettangolo.h"
 
class Quadrato : public Rettangolo {
public:
    Quadrato(double lato);
    virtual void setBase(double val);
    virtual void setAltezza(double val);
};
 
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "Quadrato.h"
 
Quadrato::Quadrato(double lato) {
    setBase(lato);
}
 
void Quadrato::setBase(double val) {
    Rettangolo::setBase(val);
    Rettangolo::setAltezza(val);
}
 
void Quadrato::setAltezza(double val) {
    Rettangolo::setBase(val);
    Rettangolo::setAltezza(val);
}
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
#include "Quadrato.h"
 
#include <iostream>
#include <vector>
 
using namespace std;
 
void test1();
void test2();
 
int main() {
    test1();
    test2();
 
    return 0;
}
 
template <class T>
void caricaRettangoli(vector<T*>& v) {
    v.push_back(new Rettangolo(2,3));
    v.push_back(new Quadrato(10));
    v.push_back(new Rettangolo(1,1));
}
 
template <class T>
void svuota(vector<T*>& v) {
    while(!v.empty()) {
        delete v.back();
        v.pop_back();
    }
}
 
void test1() {
    vector<Poligono*> poligoni;
    caricaRettangoli(poligoni);
    //poligoni.push_back(new Triangolo(4,1));  // CHALLANGE!!!
 
    for(int i = 0; i < poligoni.size(); i++) {
        cout << "Poligono " << i
             << ": perimetro = " << poligoni[i]->perimetro()
             << ", area = " << poligoni[i]->area() << endl;
    }
 
    svuota(poligoni);
}
 
void test2() {
    vector<Rettangolo*> rettangoli;
    caricaRettangoli(rettangoli);
 
    for(int i = 0; i < rettangoli.size(); i++) {
        rettangoli[i]->setBase(i+1);
        cout << "Rettangolo " << i 
             << ": perimetro = " << rettangoli[i]->perimetro()
             << ", area = " << rettangoli[i]->area() << endl;
    }
 
    svuota(rettangoli);
}
Challange! Arricchire la gerarchia con altre classi.

10 thoughts on “Classi Poligono, Rettangolo e Quadrato”

  1. Salve prof, sto facendo alcune prove con le classi virtuali, mi esce uno strano errore quando vado a compilare nella classe madre: “undefined reference to ‘vtable for nomeClasse'”
    A cosa è dovuto secondo voi?

    1. Ciao Francesco.

      L’errore dovrebbe essere dovuto alla mancanza dell’implementazione di un metodo virtuale puro. Ad esempio, considera il seguente codice:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      
      class A {
      public:
          virtual void a() = 0;
      };
       
      class B : public A {
          virtual void a();
      };
       
      int main() {
          A* i = new B();
       
          return 0;
      }

      Se provo a compilare (con g++ 4.8.2) ottengo l’errore su vtable:

      a.cpp:(.text._ZN1BC2Ev[_ZN1BC5Ev]+0x1f): undefined reference to `vtable for B'
      collect2: error: ld returned 1 exit status

      Nota che il metodo a() è virtuale puro nella classe A. La classe B estende A e dichiara un’implementazione di a(), che però è assente nel codice sorgente. Il compilatore quindi segnala l’errore.

  2. Grazie Prof per la tempestiva risposta, il problema però in questo caso non mi è dato da una classe virtuale pura, ma dal semplice costruttore della classe madre, cerco di spiegarmi:
    All’inizio il mio codice era impostato senza costruttore e dati privati nella classe madre(quindi virtuale) e con le classi figlie cn diversi dati privati. Quando andavo a compilare il costruttore delle classe figlie mi dava questo errore: “undefined reference to Madre” perchè non trovava come dice lei metodi(fatti) nella classe madre. Ora ho provato a mettere dati privati nella classe madre ed il mio codice si presenta cosi:
    class Madre
    private:
    int x;
    public:
    Madre(int x){ this->x=x;}

    class Figlia
    private:
    int y
    int z
    public:
    Figlia(int y, int k) : Madre(y), z(k)
    {
    this->y=y; this->z=k;
    }
    int main(){ Madre *figlia=new Figlia(1,2);}

    Più o meno cosi.
    c’è qualche sbaglio lampante tra queste righe?

  3. PS ho anche provato a mettere gli stessi dati privati sia nella madre che nella figlia, ma credo non c’entri molto. Grazie

  4. Salve prof, poi in quella giornata ho risolto, in pratica mi dava errore sul costruttore, ma in realtà l’errore era sulle altre funzioni, avevo inizializzato nella classe virtuale questo tipo di funzione:
    virtual bool funzione(); e non
    virtual bool funzione(){return true;}
    non sapevo che non essendo virtuali pure dovevo comunque inizializzarle.

  5. Ottimo! Riassumendo, ogni dichiarazione di metodo che non sia virtuale puro deve essere accompagnata da un’implementazione. Diversamente, viene prodotto un errore in fase di linking.

  6. Salve professore stavo provando a fare un esercizio dello scritto, ma sto avendo problemi con la funzione pop_front(). Quando per esempio devo aggiungere una persona ad una lista ereditata, tutto bene, ma quando devo estrarla, usando la semplice funzione void pop(){ pop_front(); }, non mi da problemi di compilazione, ma quando ma vado a fare qualche cout nel main, non mi compare niente!

    1. Ciao,

      il messaggio era finito nello spam, immagino che hai già trovato una soluzione. Ad ogni modo, il metodo pop_front() delle strutture STL elimina il primo elemento del container, ritornando void. Se vuoi implementare un metodo che elimina il primo elemento e lo restituisce, come per le strutture Java, devi prima salvare l’elemento, eliminarlo e quindi restituirlo. Ad esempio, per una classe MyContainer che estende std::list dovresti scrivere qualcosa del genere:

      1
      2
      3
      4
      5
      6
      
      template<class T>
      T MyContainer::pop() {
          T ret = front();
          pop_front();
          return ret;
      }

Leave a Reply

Your email address will not be published. Required fields are marked *