* * * *

Privacy Policy

Blog italiano

Clicca qui se vuoi andare al blog italiano su Lazarus e il pascal.

Forum ufficiale

Se non siete riusciti a reperire l'informazione che cercavate nei nostri articoli o sul nostro forum vi consiglio di visitare il
Forum ufficiale di Lazarus in lingua inglese.

Lazarus 1.0

Trascinare un file nel programma
DB concetti fondamentali e ZeosLib
Recuperare codice HTML da pagina web
Mandare mail con Lazarus
Stabilire il sistema operativo
Esempio lista in pascal
File INI
Codice di attivazione
Realizzare programmi multilingua
Lavorare con le directory
Utilizzare Unità esterne
TTreeView
TTreeview e Menu
Generare controlli RUN-TIME
LazReport, PDF ed immagini
Intercettare tasti premuti
Ampliare Lazarus
Lazarus e la crittografia
System Tray con Lazarus
UIB: Unified Interbase
Il file: questo sconosciuto
Conferma di chiusura di un applicazione
Liste e puntatori
Overload di funzioni
Funzioni a parametri variabili
Proprietà
Conversione numerica
TImage su Form e Panel
Indy gestiore server FTP lato Client
PopUpMenu sotto Pulsante (TSpeedButton)
Direttiva $macro
Toolbar
Evidenziare voci TreeView
Visualizzare un file Html esterno
StatusBar - aggirare l'errore variabile duplicata
Da DataSource a Excel
Le permutazioni
Brute force
Indy 10 - Invio email con allegati
La gestione degli errori in Lazarus
Pascal Script
Linux + Zeos + Firebird
Dataset virtuale
Overload di operatori
Lavorare con file in formato JSON con Lazarus
Zeos ... dietro le quinte (prima parte)
Disporre le finestre in un blocco unico (come Delphi)
Aspetto retrò (Cmd Line)
Lazarus 1.0
Come interfacciare periferica twain
Ubuntu - aggiornare free pascal e lazarus
fpcup: installazioni parallele di lazarus e fpc
Free Pascal e Lazarus sul Raspberry Pi
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal.
Creare un server multithread
guida all'installazione di fpc trunk da subversion in linux gentoo
Indice
DB concetti fondamentali e connessioni standard
Advanced Record Syntax
DB concetti fondamentali e DBGrid
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText
Advanced Record Syntax: un esempio pratico
Superclasse form base per programmi gestionali (e non)
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form
Superclasse form base per programmi gestionali (e non) #4 - wait animation
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog
Installare lazarus su mac osx sierra
immagine docker per lavorare con lazarus e free pascal
TDD o Test-Driven Development
Benvenuto! Effettua l'accesso oppure registrati.
Dicembre 04, 2024, 07:51:53 am

Inserisci il nome utente, la password e la durata della sessione.

32 Visitatori, 0 Utenti

28 Nov 2011 - OOP e Classi

Con le classi si introduce anche il discorso di programmazione orientata agli oggetti (OOP), in quanto il Free Pascal (quindi di rimando anche Lazarus) è considerato tale.
Per capire cosa si intende per programmazione orientata agli oggetti ci viene in aiuto Wikipedia che ne da una definizione ottima:

La programmazione orientata agli oggetti (OOP, Object Oriented Programming) è un paradigma di programmazione, che prevede di raggruppare in un'unica entità (la classe) sia le strutture dati che le procedure che operano su di esse, creando per l'appunto un "oggetto" software dotato di proprietà (dati) e metodi (procedure) che operano sui dati dell'oggetto stesso. La programmazione orientata agli oggetti può essere vista come una modulazione di oggetti software sulla base degli oggetti del mondo reale.
La modularizzazione di un programma viene realizzata progettando e realizzando il codice sotto forma di classi che interagiscono tra di loro. Un programma ideale, realizzato applicando i criteri dell'OOP, sarebbe completamente costituito da oggetti software (istanze di classi) che interagiscono gli uni con gli altri.
La programmazione orientata agli oggetti è particolarmente adatta a realizzare interfacce grafiche.

Sulla base di ciò Wikipedia definisce le classi in questo modo:

Nella programmazione orientata agli oggetti una classe è un costrutto di un linguaggio di programmazione usato come modello per creare oggetti. Il modello comprende attributi e metodi che saranno condivisi da tutti gli oggetti creati.
Una classe può rappresentare una persona, un luogo oppure una cosa, ed è quindi l'astrazione di un concetto implementata in un programma per computer. Fondamentalmente essa definisce al proprio interno lo stato ed il comportamento dell'entità di cui è rappresentazione. I dati che descrivono lo stato sono memorizzati nelle variabili membro, mentre il comportamento è descritto da blocchi di codice riutilizzabile chiamati metodi.

Vediamo ora i vantaggi della programmazione ad oggetti
Incapsulamento
L'incapsulamento è la proprietà per cui i dati che definiscono lo stato interno di un oggetto sono accessibili ai metodi dell'oggetto stesso, mentre non sono visibili ai clients. Per alterare lo stato interno dell'oggetto, è necessario invocarne i metodi, ed è questo lo scopo principale dell'incapsulamento. Infatti, se gestito opportunamente, esso permette di vedere l'oggetto come una black-box, cioè una "scatola nera" di cui, attraverso l'interfaccia, è noto cosa fa, ma non come lo fa.

Ereditarietà
Il meccanismo dell'ereditarietà permette di derivare nuove classi a partire da quelle già definite. Una classe derivata attraverso l'ereditarietà, o sottoclasse, mantiene i metodi e gli attributi delle classi da cui deriva (classi base, o superclassi); inoltre, può definire i propri metodi o attributi, e può ridefinire il codice eseguibile di alcuni dei metodi ereditati tramite un meccanismo chiamato overriding.
Quando una classe eredita da una sola superclasse si parla di eredità singola; viceversa, si parla di eredità multipla.
L'ereditarietà può essere usata come meccanismo per ottenere l'estensibilità e il riuso del codice, e risulta particolarmente vantaggiosa quando viene usata per definire sottotipi, sfruttando le relazioni is-a esistenti nella realtà di cui la struttura delle classi è una modellizzazione. Oltre all'evidente riuso del codice della superclasse, l'ereditarietà permette la definizione di codice generico attraverso il meccanismo del polimorfismo.

Polimorfismo
Nella programmazione ad oggetti, con il nome di polimorfismo per inclusione, si indica il fatto che lo stesso codice eseguibile può essere utilizzato con istanze di classi diverse, aventi una superclasse comune.
Piccolo esempio che spiega l'implementazione del polimorfismo con free pascal: http://www.lazaruspascal.it/index.php?topic=2333.msg14593

Vediamo un po' di codice per capire meglio, come dichiarare una classe semplice ed usarla:
Codice: [Seleziona]

type
ClasseUtenti=class
private
NomeUtente: string;
public
costructor Create();
destructor Free();
                procedure setUtente(valore: string);
                function getUtente(): string;
end;
Constructor ClasseUtenti.Create();
begin
end;
Destructor ClasseUtenti.Free();
begin
end;
procedure ClasseUtenti.setUtente(valore: string);
begin
     NomeUtente:=valore;
end;
function ClasseUtenti.getUtente(): string;
begin
     getUtente:=NomeUtente;
end;


Con queste righe di codice abbiamo appena creato la nostra prima classe che contiene il nome di un ipotetico utente. Come si può notare la variabile che conterrà il nome dell'utente si chiama NomeUtente ed è una stringa. Questa variabile (proprietà) è stata dichiarata all'interno della sezione private, ovvero non è visibile all'esterno della classe, e può essere letta o settata solo attraverso funzioni e procedure che fanno parte della classe stessa. La funzione per leggere e la procedura (metodi) per settare  il nome dell'utente sono dichiarate nella sezione public, ovvero sono visibili all'esterno della classe. Un altra cosa che va notata è che all'interno del type...end; sono presenti solo le dichiarazioni dei metodi stessi, i metodi sono scritti per intero fuori dal type...end; e per identificare che appartengono ad una classe si mette il nome della classe prima del nome del metodo separati solo da un punto. Una nota particolare va posta sulle due diciture constructor e distructor che servono per far capire quale funzione crea (allocca in memoria) la classe e quale la distrugge (deallocca dalla memoria).

Usare la classe appena creata è davvero facile, diamo un occhiata a come fare, creiamo una nuova applicazione console con questo codice:
Codice: [Seleziona]

program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp,
  { you can add units after this };
{INIZIO MIO CODICE}
type
ClasseUtenti=class
private
NomeUtente: string;
public
constructor Create();
destructor Free();
                procedure setUtente(valore: string);
                function getUtente(): string;
end;
{FINE MIO CODICE}
type

  { TMyApplication }

  TMyApplication = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

{ TMyApplication }

procedure TMyApplication.DoRun;
var
  ErrorMsg: String;
  app:ClasseUtenti; {VARIABILE DICHIARATA DA ME}
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h','help');
  if ErrorMsg'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h','help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;
  { add your program here }

  {
   dopo aver dichiarato una variabile di nome app di tipo ClasseUtenti
   ora devo far si che a questa variabile venga assegnato uno spazio in
   memoria per poterci scrivere dentro e quindi eseguo la riga successiva
   dove indico che ad app voglio assegnare NomeClasse.Costruttore
  }
  app:=ClasseUtenti.Create();
  app.setUtente('xinyiman');  {setto la variabile con il nome del mio utente, nel mio caso xinyiman}
  writeln('Utente: ',app.getUtente()); {ora vado a stampare a video il nome dell'utente inserito nella classe poco fa}
  app.Free(); {ho fatto tutto quello che dovevo con questa variabile app e quindi libero dalla memoria lo spazio che occupa richiamando il distruttore}
  // stop program loop
  Terminate;
end;

constructor TMyApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TMyApplication.Destroy;
begin
  inherited Destroy;
end;

procedure TMyApplication.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ',ExeName,' -h');
end;


{INIZIO MIO CODICE}
Constructor ClasseUtenti.Create();
begin
end;
Destructor ClasseUtenti.Free();
begin
end;
procedure ClasseUtenti.setUtente(valore: string);
begin
     NomeUtente:=valore;
end;
function ClasseUtenti.getUtente(): string;
begin
     getUtente:=NomeUtente;
end;
{FINE MIO CODICE}

var
  Application: TMyApplication;
begin
  Application:=TMyApplication.Create(nil);
  Application.Title:='My Application';
  Application.Run;
  Application.Free;
end.


Ed ecco un esempio che spiega come usare l'ereditarietà in Lazarus, ampliando l'esempio precedente.
Codice: [Seleziona]

program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp
  { you can add units after this };
{INIZIO MIO CODICE}
type
ClasseUtenti=class
private
NomeUtente: string;
public
     constructor Create(); virtual;
     destructor Free();
              procedure setUtente(valore: string);
              function getUtente(): string;
end;

type
        AdvClasseUtenti=class(ClasseUtenti)
        public
              constructor Create(); override; //il termine override significa "calpestare" o "passare sopra" e serve per dire che questo costruttore deve andare a sostituire il costruttore della superclasse
              function GetUtenteInverso(): string;
end;
{FINE MIO CODICE}
type

  { TMyApplication }

  TMyApplication = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

{ TMyApplication }

procedure TMyApplication.DoRun;
var
  ErrorMsg: String;
  app:AdvClasseUtenti; {VARIABILE DICHIARATA DA ME}
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h','help');
  if ErrorMsg'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h','help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;
  { add your program here }

  {
   dopo aver dichiarato una variabile di nome app di tipo ClasseUtenti
   ora devo far si che a questa variabile venga assegnato uno spazio in
   memoria per poterci scrivere dentro e quindi eseguo la riga successiva
   dove indico che ad app voglio assegnare NomeClasse.Costruttore
  }
  app:=AdvClasseUtenti.Create();
  writeln('Utente: ',app.getUtente()); {ora vado a stampare a video il fatto che non è stato inserito ancora nessun utente}
  app.setUtente('xinyiman');  {setto la variabile con il nome del mio utente, nel mio caso xinyiman}
  writeln('Utente: ',app.getUtente()); {ora vado a stampare a video il nome dell'utente inserito nella classe poco fa}
  writeln('Utente: ',app.GetUtenteInverso()); {ora stampo al contrario il nome dell'utente, funzione che ho aggiunto alla classe figlia}
  app.Free(); {ho fatto tutto quello che dovevo con questa variabile app e quindi libero dalla memoria lo spazio che occupa richiamando il distruttore}
  // stop program loop
  Terminate;
end;

constructor TMyApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TMyApplication.Destroy;
begin
  inherited Destroy;
end;

procedure TMyApplication.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ',ExeName,' -h');
end;


{INIZIO MIO CODICE}
Constructor ClasseUtenti.Create();
begin
     Self.setUtente('');
end;
Destructor ClasseUtenti.Free();
begin
end;
procedure ClasseUtenti.setUtente(valore: string);
begin
     NomeUtente:=valore;
end;
function ClasseUtenti.getUtente(): string;
begin
     getUtente:=NomeUtente;
end;

constructor AdvClasseUtenti.Create();
begin
     inherited Create(); //inherited significa ereditato e vuol dire che vado ad eseguire prima il costruttore della super classe e poi il codice di questo costruttore
     {ovviamente potevamo escludere la riga sopra che inizia con inherited solo che non avrebbe eseguito il costruttore della superclasse, cosa non necessaria nel nostro esempio, ma fondamentale da sapere per livelli di programmazione un po' più avanzati di questo esempio}
     Self.setUtente('NESSUN UTENTE INSERITO'); //la procedura SetUtente l'ho ereditata dalla superclasse
end;

function AdvClasseUtenti.GetUtenteInverso(): string;
var
   i: integer;
   ret,appoggio: string;
begin
     ret:='';
     appoggio:=Self.getUtente();
     i:=Length(appoggio);
     while (i>=0) do
     begin
          ret:=ret + appoggio[i];
          Dec(i); //decremento la variabile i
     end;
     GetUtenteInverso:=ret;
end;
{FINE MIO CODICE}

var
  Application: TMyApplication;
begin
  Application:=TMyApplication.Create(nil);
  Application.Title:='My Application';
  Application.Run;
  Application.Free;
end.


Vediamo ora alcune parole riservate:
private - questo significa che gli elementi qui definiti, sono disponibili o visibili da altre classi procedure o funzioni definite all'interno della stessa unit di programma.
protected - questo significa che le voci definite qui sono solo disponibili o visibili da classi che discendono da quella classe antenata,ed eredita le sue proprietà o metodi
public - questo significa che le voci definite qui sono solo disponibili per qualunque unit che includa la unit corrente in essa con la clausula Uses
published - è simile alla sezione public, ma il compilatore genera anche il tipo di informazioni che è necessario per lo streaming automatico di queste classi. Spesso la lista delle voci appare nel Object Inspector di Lazarus; se non compare una lista published,tutti i campi public appaiono normalmente in the Object Inspector.

Metodi
Methods
Un metodo è esattamente come una procedura standard o una funzione, ma può avere qualche directives.
Alcuni dei metodi di definizione di cui sopra sono etichettati con la direttiva virtual; altri sono etichettati con la direttiva override.

virtual significa che il tipo o il grado effettivo di un metodo non è noto al momento della compilazione,ma è stato selezionato in run-time a seconda di ciò che effettivamente richiama il sotto-programma sul momento. Potrebbe essere considerato un segnaposto nella definizione della classe.
override significa che in fase di esecuzione la definizione data a livello locale può prendere il posto di una definizione ereditata da una classe antenata, soprattutto se fosse virtuale. Se si desidera utilizzare il metodo definito nella classe antenata, a volte è necessario chiamare in modo specifico con la clausola inherited come visto nell'esempio precedente.

Tutti i metodi virtual o override sono metodi dinamici, tutti gli altri vengono chiamati metodi statici.

Share on Twitter! Digg this story! Del.icio.us Share on Facebook! Technorati Reddit StumbleUpon

Articles in « PROGRAMMATORE ALZATI E CAMMINA CON LAZARUS »

Comments *

Commenting option has been turned off for this article.

Recenti

How To

Utenti
  • Utenti in totale: 802
  • Latest: maXim.FI
Stats
  • Post in totale: 19240
  • Topic in totale: 2294
  • Online Today: 60
  • Online Ever: 900
  • (Gennaio 21, 2020, 08:17:49 pm)
Utenti Online
Users: 0
Guests: 32
Total: 32

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.