zwyx
Messages postés146Date d'inscriptionjeudi 22 novembre 2007StatutMembreDernière intervention21 mars 2016
-
8 janv. 2008 à 12:11
zwyx
Messages postés146Date d'inscriptionjeudi 22 novembre 2007StatutMembreDernière intervention21 mars 2016
-
10 janv. 2008 à 14:59
Bonjour à tous,
J'ai modélisé une classe (TA par exemple) qui contient l'adresse d'une instance d'une autre classe (que l'on nommera TB). Ensuite, chaque instance de la classe TB contient l'adresse de l'instance de TB suivante, de manière à constituer une liste chaînée simple.
Mon souci intervient dans le destructeur de la classe TA, quand je cherche à détruire toutes les instances de TB, en commençant bien évidemment par le dernier, pour ne pas rompre la liste.
Voici un petit schéma ASCII illustrant la modélistation, et le code du destructeur de la classe TA que j'ai écrit.
destructor TA.Destroy();
var
CurrentB: TB;
begin
if FirstB<>nil then // vérification au cas où liste chaînée vide
begin
CurrentB := FirstB; // on pointe sur la première instance de la liste
while CurrentB.NextB<>nil do // tant qu'un élément suit
begin
while CurrentB.NextB<>nil do // recherche de la dernière instace de TB constituant la liste chaînée
CurrentB := CurrentB.NextB;
CurrentB.Free; // appelle le destructeur de TB pour détruire le dernier élément
end; // while
FirstB.Free; // appelle le destructeur de TB pour détruire le premier élément
end; // if
end;
Lors de l'exécution, le code n' exécute pas le corps de la première boucle while, juste après la ligne
CurrentB := FirstB;
Voila, je vous ai tout dit. Alors si vous avez des indices pour trouver mon erreur...
zwyx
Messages postés146Date d'inscriptionjeudi 22 novembre 2007StatutMembreDernière intervention21 mars 2016 8 janv. 2008 à 14:59
Ta méthode est efficace. J'ai pu ainsi trouver une erreur lors de la création de ma liste chaînée. C'est sans doute pour cela que ma méthode de destruction initiale ne fonctionnait pas. En effet, j'avais CurrentB.NextB=nil
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 8 janv. 2008 à 19:14
ce n'est pas normal de reimplementer la méthode Free
as tu vérifier ta declaration du destructeur (dans l'interface) et de ses parents si c'est aussi des classes persos?
destructor Destroy;override; en tout cas, reimplementer le destructeur ne fera que masquer un problème qui resurgira un jour ou l'autre.
Vous n’avez pas trouvé la réponse que vous recherchez ?
zwyx
Messages postés146Date d'inscriptionjeudi 22 novembre 2007StatutMembreDernière intervention21 mars 2016 9 janv. 2008 à 17:16
Je ne vois pas en quoi c'est dangeureux de ré-écrire la méthode Free pour une classe, même si elle est générique, on peut la surcharger, non ?
Enfin je te fais confiance, j'ai effacé mes procédures Free. J'ai ajouté "override" à mes destructeurs de classe. Maintenant, l'appel à Free exécute bien le destructeur que j'ai écrit.
Une dernière question, est-ce bien "override", et non "overload" ? Si je comprend bien la nuance entre ces deux commandes, la première remplace tandis que la deuxième permet de compléter une méthode générique ?
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 9 janv. 2008 à 22:45
override permet de surcharger des methodes virtual (ou dynamic).
overload permet d'avoir 2 noms de fonctions identiques, aves des parametres differents.
si tu as une methode statique (non virtual), le pointeur sur cette methode est defini a la compilation.
si tu as une methode virtaul, le pointeur est defini a l'execution
si tu ne met pas le virtual et le override, l'adresse sera du style
AdresseDeBaseDeLaClasse + AdresseDeLaMethodeDansLaClasse
a ce moment la, c'est la ligne de code qui te permet d'acceder a la methode qui definira laquelle utiliser (en gros, le type de ta variable):
var
p: TPere;
f: TFils;
begin
f : = TFils.Create;
p := f; // meme objet (de classe TFils)
p.Test; //appel de la methode de la classe TPere
f.Test; //appel de la methode de la classe TFils
alors que les 2 variables pointent vers le meme objet !
Pour le overload, tu peux avoir 2 methodes :
procedure Test(x: integer); overload;
procedure Test(x: string); overload;
ici, selon le type du parametre que tu passe a la fonction, l'implementation correspondante sera appelée.
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 9 janv. 2008 à 22:54
Pour en revenir a ton destructeur, voila une petite explication:
Soit A: TA;
A.Free provoque les appels suivants
TObject.Free qui est implementé comme ca :
procedure TObject.Free;
begin
Self.Destroy;
end;
vu que ta methode Destroy n'est pas override, l'adresse de la fonction Destroy trouvée depend du type de la variable self, a savoir TObject.
Donc la methode appelée est TObject.Destroy.
en revanche, si tu met override a ton TA.Destroy, l'adresse trouvée de la methode Destroy dans TObejct.Free est celle de TA, puisqu'elle a ete liée au Create de ton TA.
zwyx
Messages postés146Date d'inscriptionjeudi 22 novembre 2007StatutMembreDernière intervention21 mars 2016 10 janv. 2008 à 09:45
Oula, le premier message était compliqué. Mais j'ai quand même saisi la différence entre overload et override. J'ai mieux compris ce qui se passait dans ma situation avec ton deuxième message. La destruction avec Free passe à présent toujours par le destructeur de ma classe, et non plus par celui de TObject.
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 10 janv. 2008 à 13:43
absolument pas ;)
a moins de le vouloir pour de bonnes raisons, il faut mettre le inherited dans toutes les fonctions override.
exemple :
destructor TA.Destroy; (override de TObject)
begin
inherited;
UnChampDeTA.Free;
end;
destructor TB.Destroy; (override de TA)
begin
inherited;
UnChampDeTB.Free;
end;
si tu ne met pas le inherited dans TB, l'objet UnChampdeTA ne sera pas detruit.
Le inherited dans le destroy de TA ne sert a rien, vu que TObject.Destroy ne contient aucun code. Cependant, si tu insere une classe intermediare entre TObject et TA ( TA class -> TA class(TC) ), le inherited servira a quelquechose. Donc inutile de le virer, meme si il ne sert a rien.