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 :

[Interface]Caster dans un type interface ?


Sujet :

Langage Delphi

  1. #1
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut [Interface]Caster dans un type interface ?
    Bonsoir à tous,

    j'essaie de caster une référence d'objet en une instance de mon interface en me servant du mot réservé "as", mais cela ne fonctionne pas...

    J'ai un code qui ressemble à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    IMyInterface=interface
      // plein de méthodes à implémenter
    end;
     
    TMyClasseAbstraite1=class(TInferfacedObject, IMyInterface)
      // méthodes abstraites principalement
    end;
     
    TMyClasseAbstraite2=class(TInferfacedObject, IMyInterface);
    Maintenant, j'ai un TObjectList qui stocke des TMyClasseAbstraite1 et TMyClasseAbstraite2. Leur seul tronc commun est IMyInterface. Et lorsque j'écris le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    with MonTObjectList[0] as IMyInterface do 
      ...
    je me prend un erreur à la compil'! idem avec un cast direct "IMyInterface(MyReference)"....

    "As" ne fonctionnant pas avec les type interface, que utiliser d'autre ? Et surtout, pourquoi delphi ne permet pas cela (en java c'est tout à fait légal par exemple) ?

    en gros, comment savoir si une référence d'objet est d'un type implémentant une interface, et comment récupérer une référence de ce type......

    Merci

  2. #2
    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
    Est-ce que MonTObjectList contient des références à des interfaces ou à des objets ?

    Dans le premier cas, il suffit de caster en IInterface en plus du as (TObjectList, comme son nom l'indique, ce sont des objets) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    with IInterface(MonTObjectList[0]) as IMyInterface do
    Dans le deuxième cas, alors tu t'y prends mal Parce qu'il faut soit travailler uniquement avec les objets, soit uniquement avec les interfaces. Sinon tu vas avoir des problèmes à cause du compteur de références des interfaces. Il ne faut pas confondre les interfaces avec l'héritage multiple du C++ !

  3. #3
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Citation Envoyé par sjrd
    Est-ce que MonTObjectList contient des références à des interfaces ou à des objets ?
    Il contient des références d'objets, type TMyClasseAbstraite1 ou TMyClasseAbstraite2.

    Citation Envoyé par sjrd
    Il ne faut pas confondre les interfaces avec l'héritage multiple du C++ !
    Euh, en fait je confondrais plutôt avec les interfaces de java, qui permettent de simuler un héritage multiple...
    C'est pas pour ça en delphi ? A quoi ça sert de spécifier qu'une classe hérite d'une interface ?

    Désolé de faire le gros lourd, mais j'ai pas trouvé de cours qui explique cela...

  4. #4
    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
    Citation Envoyé par Pill_S
    Euh, en fait je confondrais plutôt avec les interfaces de java, qui permettent de simuler un héritage multiple...
    Faux ! Même en Java, ce n'est pas le but des interfaces.
    Citation Envoyé par Pill_S
    A quoi ça sert de spécifier qu'une classe hérite d'une interface ?
    Une interface, c'est un moyen de manipuler des objets au travers de modules différents (et même écrits dans des langages différents) sans aucun problème de compatibilité.

    Par extension, cela permet aussi à des objets d'implémenter plusieurs comportements, et utiliser ces comportements dans du code qui ne connaît pas l'objet qui implémente ce comportement. C'est là que se situe en général l'amalgame avec l'héritage (multiple) ; pourtant il y a une sensible différence entre le fait d'hériter d'une classe parent et le fait d'implémenter une interface :
    • D'abord, lorsque ta classe implémente une interface, elle doit implémenter (et non redéfinir qui est dans le cas des interfaces un abus de langage) toutes les méthodes déclarées par l'interface. Avec les objets, d'abord tu ne peux surcharger (ou redéfinir) que les méthodes spécifiées virtual ou dynamic (et non final dans Delphi 2005 et +) mais tu ne dois surcharger que celles spécifiées abstract.
    • Ensuite, dans l'héritage multiple, la classe enfant hérite de tous les comportements déjà spécifiés dans la classe parent. Avec les interfaces, ta classe ne reçoit aucun comportement de l'interface (normal : elle n'en donne pas) et doit tous les implémenter (d'où le terme d'implémenter une interface).
    • Finalement, ... Beaucoup d'autres choses mais je n'ai pas vraiment le temps de les expliquer

    Tout ça pour dire que tu dois un peu repenser ton architecture logicielle, et manipuler tes objets exclusivement via les interfaces, ou alors pas du tout. Si tu choisis d'utiliser les interfaces, alors il te faut bien comprendre qu'une interface sert à utiliser un objet inconnu à partir des comportements qu'on sait qu'il implémente.

    Bon voilà j'espère que j'ai été clair Sinon alors je n'y arriverai pas plus et dans ce cas, tu peux éventuellement détailler réellement ce que tu veux faire et je te dirai (ou qqun d'autre bien sûr) dans quel cas tu dois utiliser des interfaces, et dans quel cas des objets (en expliquant un peu mon choix évidemment).

    PS : je pense à ça : en Java 1.3 et + tu utilises des interfaces pour gérer les événements visuels dans une applet non ? Eh bien réfléchis un peu : la classe avec laquelle tu implémentes les interfaces d'événements souris et clavier définit le comportement à avoir quand ces événements sont déclenchés

  5. #5
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Merci pour l'explication

    désolé de t'avoir donné l'impression que je comprenais pas bien le but des interfaces en java, à savoir l'expression d'un contrat abstrait que doit remplir la classe interfacée afin d'appartenir au type de l'interface, mais je ne voulais pas faire trop de parallèles entre ces langages. Enfin, le but est compris (au moins en java), mais la manière de l'implémenter en delphi l'est beaucoup moins !


    En java, on peut faire cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Object aObject=null;
    MyInterface anInstanceOfMyInterface=null;
     
    // quelle que soit la classe réelle, si elle implémente MyInterface alors cette expression renvoie true
    if(aObject instanceof MyInterface) { 
      anInstanceOfMyInterface = (MyInterface) aObject; 
     ... 
    }
    C'est ce comportement que j'aimerais retrouver en delphi, et que apparement on ne peut pas reproduire.

    Tu m'as dit qu'il fallait gérer les instances soit uniquement via des interfaces, soit via des classes, mais c'est là que je ne comprend pas trop, étant donné qu'en java on peut mélanger ces 2 types comme on veut.....

    Prenons l'exemple sur lequel je suis en train de bosser. J'ai plusieurs classes qui doivent partager une fonctionnalité commune, c'est à dire la faculté de s'écrire dans des fichiers. J'ai défini une interface qui demande l'implémentation de quelques méthodes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    IFileWriteable=interface
      public
        procedure WriteTo(var f:TextFile; const Indent:String=''); virtual; abstract;
        // ...
    end;
    Ensuite j'ai quelques classes qui héritent de divers ancêtres, et implémentent cette interface:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      TToto=class(TInterfacedObject, IFileWriteable) 
      end;
     
      TCompoTruc=class(TComponent, IFileWriteable)
      end;
    Toutes ces classes devront implémenter les méthodes contenues dans IFileWriteable afin de remplir le contrat de cette interface. Je l'ai fait et ça fonctionne sans warning à la compil + à l'exéc.

    Mais maintenant, dans une liste d'éléments (TObjectList ou TList) qui sont tous d'un type qui implémente IFileWriteable, j'aimerais récupérer les éléments non pas sous leur type réel, mais uniquement sous forme de références à l'interface, afin de pouvoir juste utiliser mes méthodes WriteTo... Les autres aspects de ces instances ne m'intéressent pas ! Leur seule caractéristique utile dans la situation où je me trouve est qu'ils implémentent tous IFileWriteable !

    Donc voilà, comment récupérer une référence sur une classe implémentant l'interface désirée ?? Vu qu'on ne peut pas transtyper vers un type interface, je ne sais pas trop comment faire...

    Je crois que c'est ma vision un peu trop "java" des interfaces qui fait que je bloque à ce niveau......


    PS: euh, j'ai réussi à me faire comprendre au fait ?

  6. #6
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Points : 15 060
    Points
    15 060
    Billets dans le blog
    1
    Par défaut Re: [Interface]Caster dans un type interface ?
    Salut,
    Citation Envoyé par Pill_S
    en gros, comment savoir si une référence d'objet est d'un type implémentant une interface, et comment récupérer une référence de ce type......
    Voir la fonction supports qui permet ce type d'opération.

    ex
    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
     
    procedure TForm1.OutlookItemSend(ASender: TObject; const Item: IDispatch; 
      var Cancel: WordBool); 
     
    var S : String; 
        UnMessage : MailItem; 
        UneReunion : MeetingItem; 
     
    begin 
      // Est-ce l'envoi d'un mail ? 
     If Supports(Item,MailItem,UnMessage) then 
      with UnMessage do 
       S:='Ajout d''un mail '+Subject; 
     
      // Est-ce l'envoi d'une demande de participation à une réunion ? 
     If Supports(Item,MeetingItem,UneReunion) then 
      with UneReunion do 
        S:='Ajout d''un contact '+SubJect+' '+SenderName; 
     
     ShowMessage(S); 
     
     //Cancel:=True; //Annule l'envoi de l'item courant. 
    end;

  7. #7
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Merci !!

    c'était exactement ça...


    mais maintenant, en lisant la doc, je viens de tomber sur ce chapitre:
    Citation Envoyé par Doc delphi6
    La déclaration d'une interface peut spécifier un identificateur globalement unique (GUID) représenté par un littéral chaîne placé entre crochets juste avant la liste des membres. La partie GUID de la déclaration doit avoir la forme suivante :

    ['{xxxxxxxx–xxxx–xxxx–xxxx–xxxxxxxxxxxx}']

    où chaque x est un chiffre hexadécimal (de 0 à 9 et de A à F). Sous Windows, l'éditeur de bibliothèque de types génère automatiquement des GUID pour les nouvelles interfaces ; vous pouvez également générer des GUID en appuyant sur Ctrl+Maj+G dans l'éditeur de code (sous Linux, vous devez utiliser Ctrl+Maj+G)
    Un GUID est une valeur binaire sur 16 octets qui identifie une interface de manière unique. Si une interface a un GUID, vous pouvez utiliser l'interrogation d'interface pour obtenir des références à ses implémentations.
    et aussi celui-là:
    Citation Envoyé par Doc delphi6
    Vous pouvez utiliser l'opérateur as afin d'effectuer des transtypages d'interface avec vérification. Ce mécanisme s'appelle l'interrogation d'interfaces ; il produit une expression de type interface depuis une référence d'objet ou une autre référence d'interface à partir du type réel (à l'exécution) de l'objet. Une interrogation d'interface a la forme suivante :

    objet as interface

    où objet est une expression de type interface, de type variant ou désignant une instance d'une classe qui implémente une interface, et où interface est une interface déclarée avec un GUID.
    L'interrogation d'interface renvoie nil si objet vaut nil. Sinon, elle transmet le GUID de interface à la méthode QueryInterface de objet et déclenche une exception sauf si QueryInterface renvoie zéro. Si QueryInterface renvoie zéro (ce qui indique que la classe de objet implémente interface), l'interrogation d'interface renvoie une référence sur objet.
    Ce qui veut dire que mon cast "with MonTObjectList[0] as MyInterface" ne fonctionnait pas uniquement à cause du fait que je n'avais pas déclaré le GUID !


    Enfin bref, tout fonctionne maintenant

    Merci de vous être penchés sur mes problèmes

  8. #8
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Citation Envoyé par Pill_S
    Enfin bref, tout fonctionne maintenant
    pas tant que ça à vrai dire... pourtant dans la doc ça paraissait clair... mais ça ne fonctionne pas...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    with MonTObjectList[i] as MonInterface do // <-- Erreur compil ici !
      WriteTo(f, Indent);
    Je me prend une erreur de compil' ! Idem si je fais comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    AFileWriteable:=MonTObjectList[i] as IFileWriteable
    et idem si j'entoure d'un bloc try...except...

    Trace: "[Erreur] DfmParser.pas(1239): Opérateur non applicable à ce type d'opérande"

    Pourtant, sjrd, je suis en train de lire un de tes tutoriels où le même code semble tourner sans problème (ici) ...... et ce qu'il y a écrit dans la doc ne doit pas être faux normalement !!!

    La seule méthode qui passe à la compil, c'est avec Supports.

    Je ne comprend plus rien ! Please help !

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 30/09/2006, 14h17
  2. [DEBUG] Found No Interfaces. Generating Code for Types
    Par Battosaiii dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 18/08/2006, 15h26
  3. Réponses: 10
    Dernier message: 15/05/2006, 10h57
  4. Réponses: 2
    Dernier message: 30/03/2006, 11h21
  5. [COM] Interface refusée dans un activeX
    Par Nalfouille dans le forum MFC
    Réponses: 1
    Dernier message: 27/03/2006, 13h58

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