OOP: Object Oriented Programming - Questo sconosciuto

 

1. CODICE+DATI=OGGETTO


Finora si sono sempre create due sezioni distinte: quella dei dati e quella del codice; un oggetto si può immaginare come l'evoluzione di un record ma che al contrario di questo contiene procedure e funzioni. Ad esempio l'oggetto TTelevisione disporrà delle proprietà Spina, Antenna, Interrutore, Volume, Frequenza ed dei metodi Accendi, Spegni, Sintonizza, AlzaVolume e AbbassaVolume. A livello di codice l'oggetto TTelevisione apparirà definito come segue:

Type TTelevisione = class
  Spina: (Inserita, Disinserita);
  Antenna: (Portatile, Normale, Satellitare);
  Interruttore: (ON, OFF);
  Volume: Byte;
  Frequenza: Byte;
  procedure Accendi;
  procedure Spegni;
  procedure Sintonizza(Canale: Byte);
  procedure AlzaVolume;
  procedure AbbassaVolume;
  constructor Create;
end;

Procedure TTelevisione.Accendi;
Begin
  If Spina = Disinserita Then
    Spina:= Inserita;
  If Interruttore = OFF Then
    Interruttore:= ON;
End;

Procedure TTelevisione.Spegni;
Begin
  If Spina = Inserita Then
    Spina:= Disinserita;
  If Interrutore = ON Then
    Interruttore:= OFF;
End;

Procedure TTelevisione.Sintonizza(Canale: Byte);
Begin
  If Frequenza <> Canale Then
    Frequenza:= Canale;
End;

Procedure TTelevisione.AlzaVolume;
Begin
  Volume:= Volume + 10;
End;

Procedure TTelevisione.AbbassaVolume;
Begin
  Volume:= Volume - 10;
End;

Constructor TTelevisione.Create;
Begin
  Frequenza:= 1;
  Spina:= Inserita;
  Interruttore:= ON;
  Volume:= 30;
  Antennza:= Satellitare;
End;

Per utilizzare l'oggetto TV basterà creare una variabile che faccia riferimento all'oggetto TTelevisione stesso, ad esempio il codice Var TV: TTelevisione; rende possibile utilizzare l'oggetto TTelevisione tramite la variabile TV.
Il Primo passo sarà quindi di inizializzare l'oggetto TV tramite l'istruzione TV:= TTelevisione.Create; cioè assegna alla variabile TV l'oggetto TTelevisione inizializzato dal constructor Create; Vi chiederete ora cosa sia un constructor, o perchè si debba seguire questa prassi, le risposte non sono semplici e dovrete per ora accontentarvi di imparare questo come un fatto scontato perchè tutti gli oggetti sono strutturati in questo modo (è buona norma far iniziare il nome di un oggetto con la T).
Come consuetudine di questo corso propongo un piccolo sorgente esplicativo.

Program WinForm;

Uses
  Forms;

Var
  frmHello: TForm;

Begin
  frmHello:= TForm.Create(nil);
  frmHello.Caption:= 'Hello Object programming';
  frmHello.Position:= poScreenCenter;
  frmHello.ShowModal;
  frmHello.free;
End.

Il programma crea una variabile frmHello derivata dall'oggetto TForm e quindi ne eredita tutti i metodi, le proprietà nonchè le caratterestiche intrinsiche non accessibili direttamente dal programmatore.
L'istruzione frmHello:= TForm.Create(nil); assegna alla variabile l'oggetto TForm inizializzato; probabilmente nel constructor create vengono settate a nulle le variabili interne, viene settata un'icona di default e preparate alcune proprietà che determinano l'aspetto della finestra (forma, colore, etc.).
Nell'istruzione seguente la proprietà caption viene cambiata in modo di visualizzare uno specifico titolo, la finestra viene quindi centrata (frmHello.Position:= poScreenCenter;) e visualizzata (frmHello.ShowModal;).
Infine è buona norma richiamare il motodo free di ogni oggetto per liberare tutta la memoria allocata dallo stesso tramite il constructor create.




lampa01.gif (2055 byte)  

E' ora spiegato perchè quando si crea una nuova Form viene creato automaticamente il codice

Type TForm1 = class(TForm);
  ...
  ...
  ...

Var
  Form1: TForm1;

Cioè viene creato un nuovo oggetto TForm1 che erdita automaticamente tutte le caratteristiche di TForm (detto oggetto Ancestor o Padre). La riga Var Form1: TForm1 rende accessibile l'oggetto TForm1 tramite la variabile Form1.


L'EREDITARIETA'



Come già accennato un oggetto può essere un "erede" di un altro. L'OOP permette però all'oggetto discentdente di modificare il comportamento standard dell'oggetto ancestor. Ad esempio supponiamo di voler creare l'oggetto TAdvancedTelevision discendente dell'oggetto TTelevision che dispone di tutte le caratteristiche della classe ancestor ma anche delle proprietà colore e forma. L'oggetto TAdvancedTelevision sarà così definito

Type TAdvancedTelevision = class(TTelevision)
Colore: (Rosso, Giallo, Verde, Blu);
Forma: (Cubo, Parallelepipedo, Standard);
constructor Create; ovverride;


constructor TAdvancedTelevision.Create;
begin
inherited Create;
Colore:= Rosso;
Forma:= Standard
end;

Si noti che dopo la definizione del prototipo del constructor Create è stata inserita la direttiva ovverride per comunicare al compilatore che si sa sovrascrivendo il construtor TTelevision, tuttavia la prima istruzione del construtor è inherited Create; che serve per ereditare il construtor dell'ancestor. Se non si provvedesse ad ereditare il vecchio constructor l'oggetto TAdvancedTelevision non avrebbe le proprietà Volume, Antenna, etc. inizializzate.


TIP lampa05.gif (2047 byte) Quando si sovrascrive un constructor la prima istruzione deve essere necessariamente inherited Create;, viceversa nella sovrascrittura di un destructor l'istruzione inherited Destructor; deve essere l'ultima, questo per evitare perdite di memoria o scorrette inizializzazioni delle variabili.

Si noti che per ereditare un oggetto si utilizza l'istruzione Type Discendente = class(Antenato).


TIP lampa04.gif (2054 byte) In effetti anche l'oggetto TTelevisione era un discendente della classe TObject, l'istruzione Type Discendente = class corrisponde alla definizione Type Discendente = class(TObject).L'oggetto TObject mette a disposizione un constructor Create, un destructor Destroy e infine un metodo free.

Un'ultima osservazione sull'ereditarietà è che un oggetto discendente può essere posto all'assegnazione (:=) con l'antenato ma non viceversa. A livello di codice questo significa che:
Punto.gif (924 byte)Discendente:= Antenato;
è sintatticamente corretto, ma viceversa
Punto.gif (924 byte)Antenato:= Discendente;
provoca un errore di compilazione. questo perchè l'oggetto ancestor non dispone di tutti i dati del discedente.


TIP lampa04.gif (2054 byte) Alcuni oggetti, specialmente quelli grafici, possono tranquillamenti lavorare con l'operatore di assegnazione, tutttavia è altamente scorretto (per motivi che non sto qui a spiegarvi). al posto dell'istruzione Bitmap1:= Bitmap2; usare quindi Bitmap1.Assign(Bitmap2).

La programmazione ad oggetti potrebbe sembrare in prima fase tanto complessa ma inutile, nella realtà è più semplice ed efficacie di quanto possa sembrare da questo capitolo che purtroppo è puramente teorico. Nella sezione "creazione di oggetti VCL" si riprenderà quanto appreso qui per metterlo in pratica con esempi in Delphi.

Corso interamente creato da VB.