Loki's notes

Un programmatore nel corpo di un fumettaro.

mercoledì 3 marzo 2010

Programmazione Orientata agli Oggetti Lez. 2

Nella prima lezione abbiamo parlato di classi, oggetti e di come utilizzarli per raggiungere un risultato finale: fare una torta.

In questa lezione ci addentreremo nei dettagli.

Nella prima lezione abbiamo definito un "robot da cucina" come una classe molto semplice con alcuni metodi accessibili:

impostaVelocità(intero),
impostaUova(intero),
monta().

In questa lezione esamineremo quei metodi nascosti che, pur non visibili, servono al funzionamento della classe.

Il costruttore o inizializzatore.

Il costruttore di una classe è il primo metodo che viene eseguito nel momento in cui si istanzia un oggetto. Questo metodo non è visibile e non è richiamabile dall'interno di altri metodi.

Serve ad inizializzare l'oggetto, o meglio i suoi attributi.

Nel nostro esempio il robot potrebbe inizializzarsi nel momento in cui viene attaccata la spina alla presa di corrente ed eseguire il seguente metodo:

controllaTensione(): metodo nascosto non accessibile dall'esterno.

Immaginando che attaccare la spina significhi istanziare un oggetto il primo metodo che verrebbe invocato in automatico sarebbe quello di controllare il voltaggio della sorgente elettrica.
controllaTensione() è un metodo nascosto, privato, e può essere eseguito solo da altri membri della classe, come lui potrebbero essercene altri, per esempio "impostaPotenza(intero)" potrebbe essere usato da impostaVelocità(intero) per far si che le lame vadano più veloci.

A fronte delle nuove informazioni possiamo riscrivere la nostra classe usando dei risolutori di visibilità:

Classe RobotBase

pubblici:
 costruttore(),
 impostaVelocità(intero),
 impostaUova(intero),
 monta(),
privati:
 controllaTensione(),
 impostaPotenza().
 intero velocità,
 intero quantità,
 intero potenza.

A prima vista il costruttore dovrebbe andare tra i metodi privati, in realtà istanziare un oggetto significa eseguire il costruttore quindi se fosse messo tra i privati l'oggetto non potrebbe essere creato.

Raffinata la conoscenza delle classi è tempo di imparare a programmare in maniera orientata agli oggetti.

L'OOP è molto semplice se non si è mai programmato un computer e si inizia da zero, molto difficile se si proviene da esperienze di linguaggi procedurali. Personalmente reputo una assoluta idiozia la tendenza ad insegnare il C++ partendo dal C, sono linguaggi totalmente diversi che condividono solo la forma e le parole chiave, il "vantaggio" di poter programmare in maniera procedurale con il C++ è fonte inesauribile di errori e di brutte pezze sopra altri errori, tutti con un unico padre: l'errata ingegnerizzazione del software. Per programmare ad oggetti bisogna imparare a pensare ad oggetti, quindi organizzare il software in oggetti, chi proviene dai procedurali pensa solo al flusso di funzioni che portano al risultato immaginado un enorme contenitore "main.cpp" che richiama una serie di procedure "incluse". Pensare ad oggetti richiede molta più fatica perché il software va costruito in piccoli pezzi autonomi, classi, che genereranno oggetti che, come i lego, assemblati tra loro costituiranno il software finale. Riprendendo l'esempio della torta della prima lezione, chi proviene dal C e affini non pensa a creare un frustino, pensa solo alla funzione di montatura delle uova, non pensa al robot ma alla procedura che amalgama l'impasto, per lui è:

uovaMontate = montaUova(uova);
impasto = impasta(uovaMontate, zucchero, farina);
torta = cuoci(burro, impasto);

Tutto è più facile e veloce, non a caso dove serve velocità ed efficienza si usa il C al posto del C++, i driver delle periferche vengono scritti in C per esempio. La nota negativa è che si può riutilizzare poco o nulla, per fare la focaccia dobbiamo riscrivere tutto, mentre con gli oggetti ci basta derivare il RobotBase e aggiungere le variabili acqua e olio più un metodo per impastarli.


L'OOP e il tool di sviluppo Qt.

Il tool di sviluppo Qt di Nokia è un ottimo strumento per programmare ad oggetti, un semplice "hello world!" in una finestra fa capire tutto ciò che abbiamo detto fino ad ora.











file: hw_mainwindow.h

#ifndef HWMAINWINDOW_H

#define HWMAINWINDOW_H


#include <QtGui/QMainWindow>

class QLabel;


/*Definiamo la classe che mostrerà la finestra
ci basta derivare la finestra principale Qt: QMainWindow
*/

class HWMainWindow : public QMainWindow //si crea la classe derivata da QMainWindow
{
public:
  HWMainWindow(QWidget * parent = 0); //Il costruttore
private:
    QLabel *hw_label; //Lo mettiamo per mostrare la parte privata, potremmo ometterlo
};

#endif //HWMAINWINDOW_H


file: hw_mainwindow.cpp

#include "hw_mainwindow.h"
#include <QtGui/QLabel>

HWMainWindow HWMainWindow(QWidget *parent)
 : QMainWindow(parent)
{
    //Creiamo l'oggetto etichetta dalla classe Qt:QLabel
    hw_label = new QLabel(this);

    //Impostiamo il testo dell'etichetta
    hw_label->setText("hello world");

    //usiamo un metodo della QMainWindow per impostare l'etichetta come oggetto principale della finestra
    setCentralWidget(label);

}


file: main.cpp

#include "hw_mainwindow.h"
#include <QApplication>

main(int argc, char *argv[])
{
  // crea un oggetto QApplication con gli stessi valori immessi al lancio del programma.
  QApplication app(int argc, char *argv[]);

  // crea un oggetto HWMainWindow, la finestra derivata che abbiamo fatto prima;
  HWMainWindow hw_MainWindow;

  // esegue il metodo di QMainWindow per visulaizzare la finestra
  hw_MainWindow.show();

  //Entra nel loop di ascolto degli eventi, in questo caso aspetta che si spinga il pulsante di chiusura
  return app.exec();
}



Se esaminiamo bene tutto il codice noteremo che abbiamo usato pochi costrutti tipici del C++, abbiamo usato gli include, il main nella sua forma standard, abbiamo definito le classi e creato gli oggetti con "new".

Tutto il resto sono solo metodi appartenenti alle classi.
Tutto è elegante e leggibile, anche non conoscendo il C++ è grosso modo intuibile cosa fanno i vari pezzi.
Il main.cpp dice solo:
Crea l'applicazione,
crea la finestra,
mostra la finestra,
aspetta che si chiuda la finestra.

Se voglio mettere un pulsante sotto l'etichetta, mi basta toccare solo la mia classe derivata HWMainWindow.










file: hw_mainwindow.cpp

#include "hw_mainwindow.h"
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QVBoxLayout>

HWMainWindow HWMainWindow(QWidget *parent)
 : QMainWindow(parent)
{
    //Creiamo l'oggetto etichetta dalla classe Qt:QLabel
    hw_label = new QLabel(this);

    //Impostiamo il testo dell'etichetta
    hw_label->setText("hello world");

    //Creiamo l'oggetto pulsante
    QPushButton *button = new QPushButton(this);
 
    //Impostiamo il testo del pulsante
    button->setText("pulsante inutile");

    //Creiamo un widget contenitore completamente invisibile all'utente
    QWidget *mainWidget = new QWidget(this);

    //Nel momento in cui usiamo più elementi grafici dobbiamo distribuirli nella finestra
    //Questa classe li distribuisce in verticale tutti all'interno del widget contenitore mainWidget
    QVBoxLayout *vlayout = new QVBoxLayout(mainWidget);

    //Mettiamo prima l'etichetta
    vlayout->addWidget(label);

    //poi il pulsante
    vlayout->addWidget(button);

    //usiamo un metodo della QMainWindow per impostare il widget contenitore come
   //oggetto principale della finestra
    setCentralWidget(mainWidget);

}

La finestra è sempre la stessa ma ora contiene oggetti in più.
Non abbiamo toccato nulla se non la classe derivata.


Daniele Granata


Creative Commons License

Questa opera è pubblicata sotto una Licenza Creative Commons.