Pascal - Cours
Vous avez vu que les objets Pascal présentent certaines caractéristiques du paradigme orienté objet. Ils implémentent l'encapsulation, le masquage des données et l'héritage, mais ils ont également des limites. Par exemple, les objets Pascal ne participent pas au polymorphisme. Les classes sont donc largement utilisées pour implémenter un comportement orienté objet approprié dans un programme, en particulier le logiciel basé sur l'interface graphique.
Une classe est définie presque de la même manière qu'un objet, mais est un pointeur vers un objet plutôt que vers l'objet lui-même. Techniquement, cela signifie que la classe est allouée sur le tas d'un programme, alors que l'objet est alloué sur la pile. En d'autres termes, lorsque vous déclarez une variable de type objet, elle prendra autant d'espace sur la pile que la taille de l'objet, mais lorsque vous déclarez une variable de type classe, elle prendra toujours la taille d'un pointeur sur la pile. Les données de classe réelles seront sur le tas.
Définition des classes Pascal
Une classe est déclarée de la même manière qu'un objet, en utilisant la déclaration de type. La forme générale d'une déclaration de classe est la suivante -
type class-identifier = class
private
field1 : field-type;
field2 : field-type;
...
public
constructor create();
procedure proc1;
function f1(): function-type;
end;
var classvar : class-identifier;
Il vaut la peine de noter les points importants suivants -
Les définitions de classe doivent relever uniquement de la partie déclaration de type du programme.
Une classe est définie à l'aide du class mot-clé.
Les champs sont des éléments de données qui existent dans chaque instance de la classe.
Les méthodes sont déclarées dans la définition d'une classe.
Il existe un constructeur prédéfini appelé Createdans la classe Root. Chaque classe abstraite et chaque classe concrète est un descendant de Root, donc toutes les classes ont au moins un constructeur.
Il existe un destructeur prédéfini appelé Destroydans la classe Root. Chaque classe abstraite et chaque classe concrète est un descendant de Root, donc toutes les classes ont au moins un destructeur.
Définissons une classe Rectangle qui a deux membres de données de type entier - longueur et largeur et certaines fonctions membres pour manipuler ces membres de données et une procédure pour dessiner le rectangle.
type
Rectangle = class
private
length, width: integer;
public
constructor create(l, w: integer);
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
Écrivons un programme complet qui créerait une instance d'une classe de rectangle et dessinerait le rectangle. C'est le même exemple que nous avons utilisé lors de la discussion des objets Pascal. Vous constaterez que les deux programmes sont presque identiques, avec les exceptions suivantes -
Vous devrez inclure la directive {$ mode objfpc} pour utiliser les classes.
Vous devrez inclure la directive {$ m +} pour utiliser les constructeurs.
L'instanciation de classe est différente de l'instanciation d'objet. La seule déclaration de la variable ne crée pas d'espace pour l'instance, vous utiliserez le constructeur create pour allouer de la mémoire.
Voici l'exemple complet -
{$mode objfpc} // directive to be used for defining classes
{$m+} // directive to be used for using constructor
program exClass;
type
Rectangle = class
private
length, width: integer;
public
constructor create(l, w: integer);
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
var
r1: Rectangle;
constructor Rectangle.create(l, w: integer);
begin
length := l;
width := w;
end;
procedure Rectangle.setlength(l: integer);
begin
length := l;
end;
procedure Rectangle.setwidth(w: integer);
begin
width :=w;
end;
function Rectangle.getlength(): integer;
begin
getlength := length;
end;
function Rectangle.getwidth(): integer;
begin
getwidth := width;
end;
procedure Rectangle.draw;
var
i, j: integer;
begin
for i:= 1 to length do
begin
for j:= 1 to width do
write(' * ');
writeln;
end;
end;
begin
r1:= Rectangle.create(3, 7);
writeln(' Draw Rectangle: ', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
r1.setlength(4);
r1.setwidth(6);
writeln(' Draw Rectangle: ', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
end.
Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -
Draw Rectangle: 3 by 7
* * * * * * *
* * * * * * *
* * * * * * *
Draw Rectangle: 4 by 6
* * * * * *
* * * * * *
* * * * * *
* * * * * *
Visibilité des membres du groupe
La visibilité indique l'accessibilité des membres de la classe. Les membres de la classe Pascal ont cinq types de visibilité -
Sr. Non | Visibilité et accessibilité |
---|---|
1 |
Public Ces membres sont toujours accessibles. |
2 |
Private Ces membres ne sont accessibles que dans le module ou l'unité contenant la définition de classe. Ils sont accessibles depuis l'intérieur des méthodes de classe ou depuis l'extérieur d'elles. |
3 | Strict Private Ces membres ne sont accessibles qu'à partir des méthodes de la classe elle-même. Les autres classes ou classes descendantes de la même unité ne peuvent pas y accéder. |
4 |
Protected C'est la même chose que private, sauf que ces membres sont accessibles aux types descendants, même s'ils sont implémentés dans d'autres modules. |
5 | Published C'est la même chose qu'un public, mais le compilateur génère des informations de type qui sont nécessaires pour le streaming automatique de ces classes si le compilateur est dans l'état {$ M +}. Les champs définis dans une section publiée doivent être de type classe. |
Constructeurs et destructeurs pour les classes Pascal
Les constructeurs sont des méthodes spéciales, qui sont appelées automatiquement chaque fois qu'un objet est créé. Nous tirons donc pleinement parti de ce comportement en initialisant de nombreuses choses via des fonctions constructeur.
Pascal fournit une fonction spéciale appelée create () pour définir un constructeur. Vous pouvez passer autant d'arguments que vous le souhaitez dans la fonction constructeur.
L'exemple suivant créera un constructeur pour une classe nommée Books et initialisera le prix et le titre du livre au moment de la création de l'objet.
program classExample;
{$MODE OBJFPC} //directive to be used for creating classes
{$M+} //directive that allows class constructors and destructors
type
Books = Class
private
title : String;
price: real;
public
constructor Create(t : String; p: real); //default constructor
procedure setTitle(t : String); //sets title for a book
function getTitle() : String; //retrieves title
procedure setPrice(p : real); //sets price for a book
function getPrice() : real; //retrieves price
procedure Display(); // display details of a book
end;
var
physics, chemistry, maths: Books;
//default constructor
constructor Books.Create(t : String; p: real);
begin
title := t;
price := p;
end;
procedure Books.setTitle(t : String); //sets title for a book
begin
title := t;
end;
function Books.getTitle() : String; //retrieves title
begin
getTitle := title;
end;
procedure Books.setPrice(p : real); //sets price for a book
begin
price := p;
end;
function Books.getPrice() : real; //retrieves price
begin
getPrice:= price;
end;
procedure Books.Display();
begin
writeln('Title: ', title);
writeln('Price: ', price:5:2);
end;
begin
physics := Books.Create('Physics for High School', 10);
chemistry := Books.Create('Advanced Chemistry', 15);
maths := Books.Create('Algebra', 7);
physics.Display;
chemistry.Display;
maths.Display;
end.
Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -
Title: Physics for High School
Price: 10
Title: Advanced Chemistry
Price: 15
Title: Algebra
Price: 7
Comme le constructeur implicite nommé create, il existe également une méthode destructrice implicite destroy à l'aide de laquelle vous pouvez libérer toutes les ressources utilisées dans la classe.
Héritage
Les définitions de classe Pascal peuvent éventuellement hériter d'une définition de classe parent. La syntaxe est la suivante -
type
childClas-identifier = class(baseClass-identifier)
< members >
end;
L'exemple suivant fournit une classe de romans, qui hérite de la classe Books et ajoute plus de fonctionnalités en fonction de l'exigence.
program inheritanceExample;
{$MODE OBJFPC} //directive to be used for creating classes
{$M+} //directive that allows class constructors and destructors
type
Books = Class
protected
title : String;
price: real;
public
constructor Create(t : String; p: real); //default constructor
procedure setTitle(t : String); //sets title for a book
function getTitle() : String; //retrieves title
procedure setPrice(p : real); //sets price for a book
function getPrice() : real; //retrieves price
procedure Display(); virtual; // display details of a book
end;
(* Creating a derived class *)
type
Novels = Class(Books)
private
author: String;
public
constructor Create(t: String); overload;
constructor Create(a: String; t: String; p: real); overload;
procedure setAuthor(a: String); // sets author for a book
function getAuthor(): String; // retrieves author name
procedure Display(); override;
end;
var
n1, n2: Novels;
//default constructor
constructor Books.Create(t : String; p: real);
begin
title := t;
price := p;
end;
procedure Books.setTitle(t : String); //sets title for a book
begin
title := t;
end;
function Books.getTitle() : String; //retrieves title
begin
getTitle := title;
end;
procedure Books.setPrice(p : real); //sets price for a book
begin
price := p;
end;
function Books.getPrice() : real; //retrieves price
begin
getPrice:= price;
end;
procedure Books.Display();
begin
writeln('Title: ', title);
writeln('Price: ', price);
end;
(* Now the derived class methods *)
constructor Novels.Create(t: String);
begin
inherited Create(t, 0.0);
author:= ' ';
end;
constructor Novels.Create(a: String; t: String; p: real);
begin
inherited Create(t, p);
author:= a;
end;
procedure Novels.setAuthor(a : String); //sets author for a book
begin
author := a;
end;
function Novels.getAuthor() : String; //retrieves author
begin
getAuthor := author;
end;
procedure Novels.Display();
begin
writeln('Title: ', title);
writeln('Price: ', price:5:2);
writeln('Author: ', author);
end;
begin
n1 := Novels.Create('Gone with the Wind');
n2 := Novels.Create('Ayn Rand','Atlas Shrugged', 467.75);
n1.setAuthor('Margaret Mitchell');
n1.setPrice(375.99);
n1.Display;
n2.Display;
end.
Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -
Title: Gone with the Wind
Price: 375.99
Author: Margaret Mitchell
Title: Atlas Shrugged
Price: 467.75
Author: Ayn Rand
Il vaut la peine de noter les points importants suivants -
Les membres de la classe Livres ont protected visibilité.
La classe Novels a deux constructeurs, donc le overload L'opérateur est utilisé pour la surcharge de fonction.
La procédure Books.Display a été déclarée virtual, afin que la même méthode de la classe Novels puisse override il.
Le constructeur Novels.Create appelle le constructeur de classe de base à l'aide du inherited mot-clé.
Interfaces
Les interfaces sont définies pour fournir un nom de fonction commun aux implémenteurs. Différents développeurs peuvent implémenter ces interfaces en fonction de leurs besoins. Vous pouvez dire que les interfaces sont des squelettes, qui sont implémentés par les développeurs. Voici un exemple d'interface -
type
Mail = Interface
Procedure SendMail;
Procedure GetMail;
end;
Report = Class(TInterfacedObject, Mail)
Procedure SendMail;
Procedure GetMail;
end;
Veuillez noter que, lorsqu'une classe implémente une interface, elle doit implémenter toutes les méthodes de l'interface. Si une méthode d'une interface n'est pas implémentée, alors le compilateur donnera une erreur.
Classes abstraites
Une classe abstraite est une classe qui ne peut pas être instanciée, seulement héritée. Une classe abstraite est spécifiée en incluant le mot symbole abstract dans la définition de classe, comme ceci -
type
Shape = ABSTRACT CLASS (Root)
Procedure draw; ABSTRACT;
...
end;
Lors de l'héritage d'une classe abstraite, toutes les méthodes marquées abstract dans la déclaration de classe du parent doivent être définies par l'enfant; de plus, ces méthodes doivent être définies avec la même visibilité.
Mot-clé statique
Déclarer des membres de classe ou des méthodes comme statiques les rend accessibles sans avoir besoin d'une instanciation de la classe. Un membre déclaré comme statique n'est pas accessible avec un objet de classe instancié (bien qu'une méthode statique le puisse). L'exemple suivant illustre le concept -
program StaticExample;
{$mode objfpc}
{$static on}
type
myclass=class
num : integer;static;
end;
var
n1, n2 : myclass;
begin
n1:= myclass.create;
n2:= myclass.create;
n1.num := 12;
writeln(n2.num);
n2.num := 31;
writeln(n1.num);
writeln(myclass.num);
myclass.num := myclass.num + 20;
writeln(n1.num);
writeln(n2.num);
end.
Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant -
12
31
31
51
51
Vous devez utiliser la directive {$ static on} pour utiliser les membres statiques.