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

Delphi Discussion :

Création d'un object sur classe dynamique


Sujet :

Delphi

  1. #1
    Membre expert
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Points : 3 575
    Points
    3 575
    Par défaut Création d'un object sur classe dynamique
    Bonjour

    j'aimerais savoir s'il est possible de créér une instance sans connaitre le type de la classe à l'avance, petit exemple dans l'idéal de ce que je souhaite:

    1ere unité: le 'uses' ne contient pas la 2eme unité
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function Instancier( MaClasse: TClass ): TObject;
    begin
      Result := MaClasse.Create; // <-- là violation d'accès...
    end;
    2eme unité
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
      TClasseA = class( TObject )
        constructor create;
        dummyA: integer
      end;
     
    procedure utilisation;
    var
      A: TClasseA;
    begin
      A := Instancier( TClasseA );
    end;
    Voila, j'ai d'autres solution pour contourner cela avec des callback, mais j'aimerais bien les éviter.

    Merci !

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur .Net / Delphi
    Inscrit en
    Juillet 2002
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .Net / Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2002
    Messages : 738
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonjour,
    A priori, ce code ne devrait même pas compiler puisque la variable A est de type TClasseA et que la fonction Instancier retourne un TObject. Le compilateur devrait retourner un type incompatible (Impossible d'affecter un TObject à un TClasseA).
    Eb.

  3. #3
    Membre chevronné Avatar de philnext
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    1 552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 552
    Points : 1 780
    Points
    1 780
    Par défaut
    C'est quoi le but en fait ?

  4. #4
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Je ne vois que ca pour l'instant mais à creuser!

    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
     
    type
      TForm1 = class(TForm)
        btn1: TButton;
        procedure btn1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
      TMaClass = class(TObject)
      private
        dummy: Integer;
      public
        procedure Show;
      end;
     
      TObjectClass = class of TObject;
     
     
    function Instancier(const AClass: TObjectClass): TObject;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    function Instancier(const AClass: TObjectClass): TObject;
    begin
      Result := AClass.Create;
    end;
     
     
    procedure TForm1.btn1Click(Sender: TObject);
    var
      A: TMaClass;
    begin
      A := TMaClass(Instancier(TMaClass)); //faut caster la :( 
      A.Show;
    end;
     
    { TMaClass }
     
    procedure TMaClass.Show;
    begin
      ShowMessage('Salut');
    end;

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    624
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 624
    Points : 754
    Points
    754
    Par défaut
    Bonjour,

    Modifies juste la procedure utilisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure utilisation;
    var
      A: TClasseA;
    begin
      A := TClasseA(Instancier(TClasseA));
    end;

    @+

  6. #6
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    ou ca

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    procedure TForm1.btn1Click(Sender: TObject);
    var
      A: TObject;
     
    begin
      A := Instancier(TMaClass);
      (A as TMaClass).Show;
    end;
    mais bon toujours un cast ....

    pour accéder a la méthode show.
    solution peut etre avec RTTI?

  7. #7
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Voila mon ultime solution ....

    unit1:

    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
     
      TForm1 = class(TForm)
        btn1: TButton;
        procedure btn1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
     
    function Instancier(const AClassStr: string): TObject;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    function Instancier(const AClassStr: string): TObject;
    var
      AClass: TPersistentClass;
    begin
      AClass := FindClass(AClassStr);
      Result := AClass.Create;
    end;
     
    procedure TForm1.btn1Click(Sender: TObject);
    var
      A: TObject;
    begin
      A := Instancier('TMaClass');
      ShowMessage(A.ClassName);
    end;
    et unit2

    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
     
    unit Unit2;
     
    interface
     
    uses Classes, Dialogs;
     
    type
      TMaClass = class(TPersistent)
      private
        dummy: Integer;
      public
        procedure Show;
      end;
     
    implementation
     
    { TMaClass }
     
    procedure TMaClass.Show;
    begin
      ShowMessage('Salut');
    end;
     
    initialization
      RegisterClass(TMaClass);
     
    end.
    mais bon pour accèder a la méthode Show de TMaClass c'est une autre histoire

  8. #8
    Membre expert
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Points : 3 575
    Points
    3 575
    Par défaut
    Merci pour vos infos !

    @ebastien
    si si, ca compile, mais j'ai une violation d'accès au moment du create comme spécifié dans le code que je montre (ca m'étonne qu'à moitié d'ailleurs...)

    @Philnext
    J'ai simplifié au maximum pour montrer uniquement ce que je souhaite.
    Mon objectif, c'est que j'ai une unité qui gère une TStringList avec des object attachés. Ces objets sont instanciés dans cette unité, mais peuvent être de differents type (le type est fourni via une paramètre de type TClass...)
    Comme cette unité est générique, hors de question pour moi, qu'elle "connaisse" les unités utilisatrices ou sont effectivement déclarées ces classes.

    @Kafeine
    Ta 1ere approche avec "class of" m'interesse, je vais creuser
    Pour le cast c'est pas grave, cela est même nécessaire, l'unité utilisatrice connait ses objets donc rien d'anormal à caster par la suite.
    (en réalite, l'objet instancié avec une certaine classe, est stocké dans un objet générique TObject puisque dans une TStringList... donc le cast en utilisation est tout à fait normal par la suite)
    Par contre,

    @Fabrice
    Effectivement, il manquait un cast dans ma proc. "utilisation", mais là n'était pas le problème

  9. #9
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par TicTacToe
    Pour le cast c'est pas grave, cela est même nécessaire, l'unité utilisatrice connait ses objets donc rien d'anormal à caster par la suite.
    (en réalite, l'objet instancié avec une certaine classe, est stocké dans un objet générique TObject puisque dans une TStringList... donc le cast en utilisation est tout à fait normal par la suite)
    ok je vois mais la 2eme solution est la pour solutionner ce qui suit

    Citation Envoyé par TicTacToe
    1ere unité: le 'uses' ne contient pas la 2eme unité
    d'ou met soucis de cast sans l'unité dans uses c'est dur

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 262
    Points
    25 262
    Par défaut
    Tu devrais regarder la TCollection et TCollectionItem, il a ce genre de mécanisme, sinon, j'ai aussi ce genre de code

    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
    type
      TLectureType = (ltLecture1, ltLecture2);
      TResultatClass = class of TResultat;
     
      TResultat = class(TPersistent)
      ...
      end;
     
      TResultatLecture1 = class(TResultat)
      ...
      end;
     
      TResultatLecture2 = class(TResultat)
      ...
      end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const
       RESULTAT_CLASSES: array[TLectureType] of TResultatClass = (TResultatLecture1, TResultatLecture2);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ...
    AResultat := RESULTAT_CLASSES[TypeLecture].Create();
    ...
    Et cela fonctionne sans problème ...

    ou Encore

    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
    type
       TAssociatedEdit = class(TEdit)
       private
          FKeyField: string;
          FKeyValue: string;
       published
          property KeyField: string read Fkeyfield write FKeyField;
          property KeyValue: string read Fkeyvalue write FKeyValue;
       end;
     
       TAssociatedCheckBox = class(TCheckBox)
       private
          FKeyField: string;
          FKeyValue: string;
       public
          procedure Click; override;
       published
          property KeyField: string read Fkeyfield write FKeyField;
          property KeyValue: string read Fkeyvalue write FKeyValue;
       end;
     
       TAssociatedField = class(TObject)
       public
         FieldName: string;
         Value: string;
         AssociatedClass: TWinControlClass;
         constructor Create(const AName, AValue: string; AClassType: TWinControlClass);
       end;
     
     
    { TAssociatedField }
     
    constructor TAssociatedField.Create(const AName, AValue: string; AClassType: TWinControlClass);
    begin
       FieldName := AName;
       Value := AValue;
       AssociatedClass := AClassType;
    end;
    et à un moment j'ai

    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
     
    function TCensoredForm.AffectClickAndCaption(...; Name, Value: string; const ClassType: TWinControlClass = nil): TMenuItem;
    begin
       Result := TMenuItem.Create(Self);
       ...
       Result.Tag := Integer(TAssociatedField.Create(Name, Value, ClassType))
     
       MenuRoot.Add(Result);
    end;
     
    procedure TCensoredForm.AddComponent(Menu: TMenuItem);
    var
       Association: TAssociatedField;
       AddedControl: TWinControl;
       UniqueName: Int64;
    begin
       if not Assigned(Menu) then Exit;
       if Menu.Tag = 0 then Exit;
       Association := TAssociatedField(Menu.Tag);
     
       QueryPerformanceCounter(UniqueName);
     
       AddedControl := Association.AssociatedClass.Create(Self); 
       AddedControl.name := '_' + FormatDateTime('YMDHNS', Now()) + IntToStr(UniqueName) + IntToStr(Random(1000));
       AddedControl.Left := CurrentPoint.X;
       AddedControl.Top := CurrentPoint.Y - AddedControl.Height;
       AddedControl.Parent := PageControlDynamic.ActivePage;
    ...

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    624
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 624
    Points : 754
    Points
    754
    Par défaut
    Il y a la solution d'implémenter la pattern Fabrique ou Fabrique abstraite.
    Comment faire cela?
    Chaque classe enregistrée dans la fabrique à l'aide de RegisterClass aura une fonction (virtuelle ou surchargée)que la factory appelera.
    Le stoquage se fera de manière usuelle dans une TClassList plutôt qu'une stringlist.

  12. #12
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 262
    Points
    25 262
    Par défaut
    On dirait un copier coller d'un tutoriel Dot Net mal traduit ...

    Ensuite sa TStringList semble stocker les objets et non les classes d'après ce que j'ai compris !

  13. #13
    Membre expert
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Points : 3 575
    Points
    3 575
    Par défaut
    Merci à tous !

    ca marche, je me suis servi des "class of" qui sont exactement ce que je recherchais pour mon cas

    @Kafeine
    Merci de m'avoir mis sur la voie !

    @ShaiLeTroll
    Effectivement, les TCollectionItem et TCollectionItemClass sont un bon exemple, et j'avais déjà jeté un coup d'oeil, étant donné que c'est l'exemple donné dans l'aide sur "class of"


    merci a+

  14. #14
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    624
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 624
    Points : 754
    Points
    754
    Par défaut
    Tiens on dirait du code de newbies copier coller sur le travail des collégues.
    Renseignes toi sur le pattern fabrique avant d'écrire des énormités!
    Une fabrique d'objets instancie précisemment ces objets via des classes.
    Comment peut t'il en être autrement?

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 262
    Points
    25 262
    Par défaut
    Effectivement, c'est du code dans des programmes écrits par des collègues que j'ai modifié et dont j'ai ajouté ce type de syntaxe pour justement rendre le code plus souple ... alors t'es gentil mais le newbies, il a 8 ans de carrière c'est déjà pas si mal ...

    j'aurais pu copier le code de la couche de persistance que j'ai écrite, mais noyez dans le RTTI, j'ai un peu de mal à donner des exemples simple au sujet du "Class of", l'utilisation d'une TClassList avec le mécanisme de recensement, lorsque l'on utilise l'instanciation d'objet via le flux de composant persistant de Delphi, tel que des DFM (issu d'un XML transformé via un XSL pour obtenir un DFM facilement chargeable sans effort, sans TXMLDocument avec un mapping manuel ...)

    Alors sinon, tu m'excusera d'avoir juste survolé le bouquin sur le Design Patterns en C# du Bureau (je fut apprenti, j'ai tout appris sur le tas, j'ai peu lu de bouquin alors comme je n'ai vu les patterns qu'avec Java et .Net, tu m'excusera de l'honteux amalgame), je n'ai surement pas le bon vocabulaire (il est en anglais et je suis terriblement mauvais en anglais, alors je n'ose pas traduit les mots en français, qenre fichiers waves -> ondes, ça sonne si mal ...), mais ta formulation dans ton poste était très étrange à mon gout ("Comment faire cela?") ... cela faisait très prof ...

  16. #16
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Oh eh doucement les gens Pas la peine de traiter tout le monde de débutant. Ce sujet est déjà assez intéressant et pas évident en soi.

    Maintenant la plupart des solutions traitées jusqu'ici étaient très bonnes. La fabrique d'objets est en particulier la solution ultime, je pense, en cas de classes tout à fait générales (descendantes de TObject).

    Mais le langage Delphi permet une solution beaucoup plus intéressante s'il s'agit d'instances de classes qui dérivent toutes d'un ancêtre commun déjà suffisamment personnalisé pour que tous les descendants aient un constructeur semblable (mêmes paramètres).

    Cette solution est d'ailleurs utilisée par la VCL avec le type TComponent, qui je vous le rappelle, a un constructeur virtuel, que tout nouveau descendant se doit de surcharger.

    L'idée est donc d'avoir une classe de base qui possède un constructeur virtuel, et que tous les descendants surchargent ce constructeur. Ensuite, on peut utiliser un class of pour passer le type en paramètre. En déclarant ce type comme class of TAncetreCommun, on peut faire appel directement au constructeur virtuel.

    Example :
    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
    type
      TAncetreCommun = class
      public
        constructor Create(Param : integer); virtual;
      end;
     
      TAncetreCommunClass = class of TAncetreCommun;
     
      TMaListe = class
      private
        FItemClass : TAncetreCommunClass;
      public
        function Add : TAncetreCommun;
      end;
     
    function TMaListe.Add : TAncetreCommun;
    begin
      Result := FItemClass.Create(5);
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    type
      TDescendant = class(TAncetreCommun)
      public
        constructor Create(Param : integer); override;
      end;
     
    TMaListe.Create(TDescendant);

  17. #17
    Membre expert
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Points : 3 575
    Points
    3 575
    Par défaut
    Farpaitement Sjrd

    C'est exactement ce que j'ai fais ( dans le principe) ! Tu as bien résumé la situation.

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 14/02/2014, 13h29
  2. [POO] Création de classes dynamiquement
    Par Umlist dans le forum Langage
    Réponses: 3
    Dernier message: 05/11/2009, 21h28
  3. Généricité et création de classes dynamiques
    Par virulent dans le forum Langage
    Réponses: 4
    Dernier message: 11/09/2009, 09h28
  4. Javadoc sur classes n'héritant pas de java.lang.Object
    Par superpoupou dans le forum EDI et Outils pour Java
    Réponses: 2
    Dernier message: 30/05/2008, 17h41
  5. Réponses: 13
    Dernier message: 27/02/2007, 11h31

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