IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Créer des objets sur la pile ?


Sujet :

Langage Delphi

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 33
    Points : 28
    Points
    28
    Par défaut Créer des objets sur la pile ?
    J'essaie d'adapter un programme C++ trouvé dans un bouquin pour comprendre la création des objets sur la pile mais j'ai pas dû tout comprendre...
    voici le code C++
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    class O2
    {
        public:
            void procedureO2()
            {
                cout << "Appel procedure de O2" << endl;
            }
    };
     
    class O1
    {
        private:
            O2* objO2; /* pointeur vers un objet de type O2 */
     
        public:
            O1(O2* objO2)
            {
                this->objO2 = objO2; /* passage du référent */
            }
     
            void ProcedureO1()
            {
                objO2 -> procedureO2();  /* l'envoi de message */
            }
    };
     
    int main(int argc, char* argv[])
    {
        O2* obj2Tas  = new O2();                /* un objet construit dans le tas */
        O2  obj2Pile;                           /* un objet construit sur la pile */
     
        O1* obj1Tas  = new O1(  obj2Tas  ); /* passage du référent */
        O1* obj11Tas = new O1( &obj2Pile ); /* passage du référent de l'objet pile */
     
        O1 obj1Pile (  obj2Tas  );
        O1 obj11Pile( &obj2Pile );
     
        obj1Tas ->procedureO1();
        obj11Tas->procedureO1();
     
        obj1Pile .procedureO1();
        obj11Pile.procedureO1();
        
        return 0;
    }
    voici mon adaptation en delphi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
     
    unit O1;
     
    interface
     
    uses O2;
     
    type
      TO1 = class (TObject)
      private
        objO2: TO2; // pointeur vers un objet de type TO2
      public
        constructor Create(obj02: TO2);
        procedure ProcedureO1;
      end;
     
    implementation
     
    constructor TO1.Create(obj02: TO2 );
    begin
      self.objO2 := obj02; //passage du référent
    end;
     
    procedure TO1.ProcedureO1;
    begin
      objO2.ProcedureO2; //l'envoi de message
    end;
     
    end.
    //***************
    unit O2;
     
    interface
     
    type
      TO2 = class (TObject)
      public
        procedure ProcedureO2;
      end;
     
    implementation
     
    procedure TO2.ProcedureO2;
    begin
      writeln('Appel procedure de TO2');
    end;
     
    end.
    //***************
    program UML2;
     
    {$APPTYPE CONSOLE}
     
    uses
      SysUtils,
      O1 in 'O1.pas',
      O2 in 'O2.pas';
     
    var
      obj1Tas, obj11Tas, obj1Pile, obj11Pile: TO1;
      obj2Pile, obj2Tas: TO2;
    begin
        obj2Tas  := TO2.Create; // un objet construit dans le tas
     
        obj1Tas  := TO1.Create( obj2Tas ); // passage du référent
        obj11Tas := TO1.Create( obj2Pile ); // passage du référent de l'objet pile
     
        obj1Pile.Create( obj2Tas ); //<-- cree violation d'acces dans constructeur
        obj11Pile.Create( obj2Pile );//<-- cree violation d'acces dans constructeur
     
        obj1Tas.ProcedureO1;
        obj11Tas.ProcedureO1;
     
        obj1Pile.procedureO1;
        obj11Pile.procedureO1;
     
        obj1Tas.free;
        obj11Tas.free;
        obj2Tas.free;
    end.
    Merci d'avance !

  2. #2
    Expert éminent sénior

    Avatar de Nono40
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2002
    Messages
    8 640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2002
    Messages : 8 640
    Points : 19 101
    Points
    19 101
    Par défaut
    Oui, bon la traduction n'est pas à la lettre. Et il semble que tu n'ai pas saisi la nuance entre O2 et O2*

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    O2* obj2Tas  = new O2();                /* un objet construit dans le tas */ 
    O2  obj2Pile;                           /* un objet construit sur la pile */
    Signifie que Obj2Tas est un pointeur vers une variable de type O2. Donc seul le pointeur est dans la pile. L'objet est créé dans le tas. Dans l'ordre il faut réserver la mémoire de la variable pointée puis l'objet qui sera pointée par la variable ( si je ne suis pas clair il faut me le dire )

    La traduction exacte est donc la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    type 
      PO2 = ^TO2; // Type pointeur sur un objet ( O2* en C )
      TO2 = class (TObject) 
      public 
        procedure ProcedureO2; 
      end; 
     
    procedure TO2.ProcedureO2;
    begin
      ShowMessage('Appel procedure de TO2');
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    Var Obj2Tas : ^T02;  // Pointeur vers un objet
    Obj2Pile : T02;
    Begin
      // Il faut déjà reserver la place de la varible objet avant de créer l'objet :
      New(Obj2Tas);
      // La variable existant, on peut créer l'objet
      Obj2Tas^:=TO2.Create;
     
      // Pour l'objet pile, la variable existe déjà ( dans la pile justement )
      // on peut alors créer directement l'objet.
      Obj2Pile:=TO2.Create;
     
      // Appels
      Obj2Tas^.ProcedureO2;
      Obj2Pile.ProcedureO2;
     
      // Pour les libération, il faut procéder à l'envers :
      Obj2Pile.Free;
     
      Obj2Tas^.Free;
      Dispose(Obj2Tas);
    End;
    Maintenant le cas de TO1. Voici déjà la traduction de l'objet lui même. La remarque principale est que tu as oublier l'appel du constructeur de la classe parent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    type
      TO1 = class (TObject)
      private
        objO2: PO2; // pointeur vers un objet de type TO2
      public
        constructor Create(obj02: PO2);
        procedure ProcedureO1;
      end;
     
    constructor TO1.Create(obj02: PO2 );
    begin
      Inherited Create; // NE PAS OUBLIER !!!
      self.objO2 := obj02; //passage du référent
    end;
     
    procedure TO1.ProcedureO1;
    begin
      // objO2 est un pointeur, c'est donc ^. qu'il faut utiliser
      objO2^.ProcedureO2; //l'envoi de message
    end;
    Voici ensuite la création et appels. De même que pour TO2, tu as confondu O1 et O1 *. Le paramètre à passer dans le constructeur de T01 est un pointeur vers un objet de type TO2. Dans le cas de l'objet pile Obj2Pile, il faut en obtenir l'adresse avec l'opérateur @. @ est la traduction directe de & en C.
    Pour la création des objets, grosse erreur : tu appel create sur un objet non créé, il faut faur MonObjet:=TMonObjet.Create().

    Voici le code complet des créations/destructions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    procedure TForm1.Button2Click(Sender: TObject);
    Var Obj2Tas : PO2;  // Pointeur vers un objet
        Obj2Pile : TO2; // Objet
        Obj1Tas,Obj11Tas : PO1;    // Pointeurs vers des objets
        Obj1Pile,Obj11Pile : TO1; //Objets
    Begin
      // Il faut déjà réserver la place de la variable objet avant de créer l'objet :
      New(Obj2Tas);
      // La variable existant, on peut créer l'objet
      Obj2Tas^:=TO2.Create;
     
      // Pour l'objet pile, la variable existe déjà ( dans la pile justement )
      // on peut alors créer directement l'objet.
      Obj2Pile:=TO2.Create;
     
      // Obj1Tas doit être crée comme Obj2Tas
      New(Obj1Tas);
      // Obj2Tas est un pointeur, donc on le passe directement
      Obj1Tas^:=TO1.Create(Obj2Tas);
     
      // Obj11Tas doit être crée comme Obj2Tas
      New(Obj11Tas);
      // Obj2Pile est un objet, il faut donc passer son adresse
      Obj11Tas^:=TO1.Create(@Obj2Pile);
     
      // Obj1Pile est un objet, on le crée directement
      Obj1Pile:=TO1.Create(Obj2Tas);
     
      // Obj11Pile est un objet, on le crée directement
      Obj11Pile:=TO1.Create(@Obj2Pile);
     
      // Appels
      Obj1Tas^.ProcedureO1;
      Obj11Tas^.ProcedureO1;
      Obj1Pile.ProcedureO1;
      Obj11Pile.ProcedureO1;
     
      // Pour les libération, il faut procéder à l'envers :
      Obj11Pile.Free;
      Obj1Pile.Free;
     
      Obj11Tas^.Free;
      Dispose(Obj11Tas);
      Obj1Tas^.Free;
      Dispose(Obj1Tas);
     
      Obj2Pile.Free;
      Obj2Tas^.Free;
      Dispose(Obj2Tas);
    end;
    Bien sur si tu as des questions...n'hésite pas
    Delphi :
    La F.A.Q. , 877 réponses à vos questions !
    264 sources à consulter/télécharger !

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 33
    Points : 28
    Points
    28
    Par défaut
    Je tiens tout d'abord à te remercier pour toutes ces infos...
    mais cela m'ammène à te poser d'autres questions !

    A. Le constructeur

    La raison pour laquelle je ne mets pas (pour l'instant...) de constructeur lorsque la classe que je créé hérite directement de TObject c'est qu'après avoir fait des essais j'ai remarqué (à tort ?) que, la méthode constructeur 'Constructor Create' ne sert qu'a initialiser les données (variables ou objets) et que c'est l'instruction suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    MonObjet := TMaClasse.Create;
     
    MonObjet := TMaClasse.Toto;
    qui permet d'allouer de la mémoire lors de la création des objets, et non pas la méthode "Constructor Create" puisque si je déclare un constructeur "Constructor Toto" mon objet sera également instancié .
    c'est pourquoi je ne l'appelle pas puisque la méthode Create définie par TObject n'initialise aucune données (j'en suis pas si sûr car je n'ai pas accès au source de TObject)...


    B.La mémoire pile

    J'ai lu que (l'orienté objet: eyrolles) la mémoire pile était utilisé pour les variables et que l'on pouvait l'utiliser pour les objets temporaires ce qui permettait de ne pas être obligé de supprimer l'objet puisqu'il était supprimé automatiquement à la sortie du bloc dans lequel il avait été créé(commme les variables) mais dans la solution que tu me donnes tu es obligé de libérer les objets piles !, je ne comprends donc plus son intérêt...

    C.fonctionnement de la mémoire pile

    (c'est la mémoire située dans le processeur ?)

    Donc si j'ai compris, la mémoire pile sert à stocker les variables temporaires, on a donc directement accès à leurs valeurs.
    Elle sert aussi à stocker les variables de type pointeurs.

    D.La mémoire tas

    (c'est la mémoire RAM ?)

    cette mémoire sert à stocker les objets (structure, enregistrement, tableau...) et on y a donc accès par l'intermédiaire des variables de type pointeurs, c-a-d de manière indirecte.

    D.fonctionnement de la mémoire tas

    Si l'on créé un tableau dynamique, qui peut par exemple stocker 3 objets, on remplit ce tableau puis l'on décide d'agrandir ce tableau, mais entre temps d'autres objets ont été stocké dans la mémoire.
    Que se passe t'il quand on va agrandir ce tableau?
    D.1
    ce tableau est recréé dans la mémoire tas pour que tous les objets se trouvent à la suite ?
    D.2
    un pointeur est créé automatiquement à la fin du premier tableau de manière à pointer automatiquement sur l'autre partie du tableau ?


    Voila, pour ces quelques questions, j'en garde d'autres sous le coude car elles dépendent de ces réponses..
    Merci d'avance aux personnes prenant du temps pour m'éclaircir les idées.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2002
    Messages : 69
    Points : 77
    Points
    77
    Par défaut
    Il me semble qu'en Delphi on ne peut justement pas créer d'objets sur la pile

    MonObj: TMonObjet -> c'est un pointeur

    c'est comme en JAVA, on ne manipule que des pointeurs sans le voir.
    Mes programmes : www.antp.be/software/fr/

  5. #5
    Invité
    Invité(e)
    Par défaut
    Exact, le Pascal Objet ne permet pas d'instancier des objets dans la pile.
    On n'utilise que des pointeurs sur ces objets mais le langage le reconnaît et on peut utiliser le . plutôt que des déférencements ^.
    Quand on fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure UneProc ;
    var MonObject: TMonObjet ;
    begin
      MonObjet := TMonObjet.Create ;
      MonObjet.MonChamp := 2 ; // déférencement de pointeur sans ^
    end;
    La variable MonObjet est un pointeur qui est sur la pile, et elle pointe sur un objet alloué dans le tas.

  6. #6
    Candidat au Club
    Inscrit en
    Mars 2002
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 4
    Points : 4
    Points
    4
    Par défaut
    La Pile, cette zone mémoire est gérée via un registre qui est le pointeur de pile quand j'écris

    c:=function add(a,b:integer):integer;

    et que j'appelle cette fonction :

    le contenu de a est placé dans la pile, ensuite le contenu de b, ensuite l'adresse de la prochaine instructio et on appelle le code de la add, ensuite le résultat est placé dans la pile.

    Au retour, il faut extraire de la pile le résultat et le placer dans c.

    Il existe également du code pour nettoyer la pile sinon celle-ci grandit, grandit,.... et paf STACK OVERFLOW (plus de place).

    Pour savoir qui nettoie et l'ordre d'empilement des paramètres, il faut ajouter une directive comme stdcall; pascal; consulter "CONVENTIONS D'APPEL' dans l'aide en ligne.

    Quand on crée des variables temporaires, elle sont également stockées dans la pile, car l'accès y est très rapide.

    LE TAS

    Il s'agit de mémoire demandée et fixée, une demande est faite à windows de fournir un bloc de taille définie et les données y sont copiées. Pour y accéder il faut passer par un système assez compliqué d'adressage en interne, et elle est moins rapide mais il y en a beaucoup plus.


    Normalement lorsque le tableau est redimensionné, on redemande une zone mémoire plus grande, on copie le contenu, on redonne l'ancien bloc mémoire au système et on obtient son nouveau bloc.

    Ceci predn du temps et c'est la raison pour laquelle, il faut éviter de redimensionner dans des boucles, etc.
    L'ordinateur à toujours tort tant que l'on ne trouve pas l'erreur.

  7. #7
    Expert éminent sénior

    Avatar de Nono40
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2002
    Messages
    8 640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2002
    Messages : 8 640
    Points : 19 101
    Points
    19 101
    Par défaut
    Citation Envoyé par Cornell
    Je tiens tout d'abord à te remercier pour toutes ces infos...
    mais cela m'ammène à te poser d'autres questions !
    Je n'ai pas eu le temps de répondre plus tôt... Bon j'y vais :

    A. Le constructeur
    Non, un conrstructeur ne fait pas qu'initialiser les données, il alloue de la mémoire pour le stockage de l'objet. De plus il vaut mieux conserver Create comme constructeur et de toujours appeler le constructeur hérité. Car comme ceci tu ne te soucis pas de savoir si la classe parente à des données ou non à initialiser.

    B.La mémoire pile
    La mémoire pile est la mémoire des variables locales et des paramètres des procédures et fonctions, elle sert aussi à conserver l'adresse de retour des fonctions et procédures en cas d'appel.
    Toutes les variables locales de la pile sont effectuivement libérées à la fiin de la fonction. Mais attention : Certaines variables utilisent de la mémoire globale sans le dire et qu'il faut exeplicitement libérer.
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Function Tata:Integer;
    Var Obj:TMonObjet;
    Begin
      Obj:=TMonObjet.Create;
      //...
      Obj.Free;
    End;
    Ici MonObjet est bien une variable située dans la pile, mais le contructeur de l'objet ( Create ) utilise de la memoire globale ( anciennement appelée TAS dans le TurboPascal ) pour créer l'objet. Cette mémoire n'est pâs libérée à la fin de la fonction. Il faut donc appeler la méthode Free avant la fin pour ne pas perdre la mémoire allouée.

    Si on revient à l'exemple complet du début, il y avait des variables de type TO2 et de type PO2, PO2 étant un pointeur vers un type TO2.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Function Tata:Integer;
    Var O2:PO2;
    Begin
      New(PO2);
      O2^:=TO2.Create;
      //...
      O2^.Free;
      Dispose(O2)
    End;
    Ici O2 est un pointeur situé dans la pile. La émoire attribuée au pointeur par la fonction New(), n'est jamais prise dans la pile. C'est pourquoi elle doit aussi être libérée avant la fin de la procédure.

    C.fonctionnement de la mémoire pile
    Citation Envoyé par Cornell
    (c'est la mémoire située dans le processeur ?)
    Donc si j'ai compris, la mémoire pile sert à stocker les variables temporaires, on a donc directement accès à leurs valeurs.
    Elle sert aussi à stocker les variables de type pointeurs.
    Non la mémoire est aussi situé dans la RAM, mais elle est utilisée avec des registres spéciaux du processeur. Elle contient les paramètres des fonctions, et les variables locale qu'elles soitn de type pointeurs ou non. Mais les objet pointés et les constructions d'objets ne sont jamais dans cette pile.

    D.La mémoire tas
    Citation Envoyé par Cornell
    (c'est la mémoire RAM ?)
    cette mémoire sert à stocker les objets (structure, enregistrement, tableau...) et on y a donc accès par l'intermédiaire des variables de type pointeurs, c-a-d de manière indirecte.
    Oui, mais avec les objets on a l'impression que l'accès est direct. Attention pour le type enregistrement : il peut aussi être dans la pile si une variable locale est de type enregistrement. Les enregistrements ne sont situés dans le tas que s'ils sont créés avec des pointeurs.

    E.fonctionnement de la mémoire tas
    Citation Envoyé par Cornell
    Si l'on créé un tableau dynamique, qui peut par exemple stocker 3 objets, on remplit ce tableau puis l'on décide d'agrandir ce tableau, mais entre temps d'autres objets ont été stocké dans la mémoire.Que se passe t'il quand on va agrandir ce tableau?
    Le tableau est déplacé par Delphi dans un emplacement suffisant pour qu'il soit contigu ( du moins je pense...). Mais c'est une question que l'on à pas besoin de se poser, c'est le problème de Delphi de gérer la mémoire.
    Delphi :
    La F.A.Q. , 877 réponses à vos questions !
    264 sources à consulter/télécharger !

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 33
    Points : 28
    Points
    28
    Par défaut
    merci à tous pour ces réponses et surtout à toi nono40 !

  9. #9
    Membre habitué
    Développeur .NET
    Inscrit en
    Juin 2002
    Messages
    274
    Détails du profil
    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2002
    Messages : 274
    Points : 174
    Points
    174
    Par défaut
    Salut,
    Tu peux aussi consulter le tutoriel suivant pour plus de renseignements :
    http://cyberzoide.developpez.com/info/turbo/chap23.php3
    Ce n'est plus adapté à Delphi, mais ça te donnera une idée..
    A+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 08/05/2013, 17h18
  2. Réponses: 0
    Dernier message: 23/06/2008, 16h58
  3. [DOM] Créer des objets rectangles en cliquant sur un boutton
    Par shaun_the_sheep dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 13/03/2008, 18h59
  4. [C#] Créer des objets Winform personnalisés
    Par KibitO dans le forum Windows Forms
    Réponses: 8
    Dernier message: 31/05/2005, 17h09
  5. quel langage pour créer des "applications" sur 1 s
    Par jaribu dans le forum Langages de programmation
    Réponses: 7
    Dernier message: 30/07/2003, 14h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo