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

Visual C++ Discussion :

implémentation d'interfaces multiples : limitation de C++ ou du compilo VS2005 ?


Sujet :

Visual C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    731
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 731
    Points : 574
    Points
    574
    Par défaut implémentation d'interfaces multiples : limitation de C++ ou du compilo VS2005 ?
    Bon, je m'explique ;
    suite à une implémentation de Garbage Collector enfin bref passons ; je viens de m'apercevoir que l'ordre de déclaration de l'implémentation d'interfaces dans une classe à une importance (chose que je n'ai jamais vue en C# et en Java).

    Je m'explique, voilà mon exemple 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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    interface I1
    {
    public :
    	virtual void SetI1 () = 0;
    };
     
    interface IInutil
    {
    public :
    	virtual void SetIInutil () = 0;
    };
     
    class JeCollectionneCeQuiDerivedeI1
    {
    public :
    	void AddElement (I1* param)
    	{
    		CString coincoin("coin coin");
    	}
    };
     
    class MaClasseQuiHeriteDesDeuxInterface : public I1, public IInutil
    {
    public :
    	MaClasseQuiHeriteDesDeuxInterface (JeCollectionneCeQuiDerivedeI1& jccqdi)
    	{
    		jccqdi.AddElement(this);
    	};
    	void SetI1 () {};
    	void SetIInutil () {};
    };
    En voici l'utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    			JeCollectionneCeQuiDerivedeI1 jccqddi;
    			MaClasseQuiHeriteDesDeuxInterface* mcqhddi = new MaClasseQuiHeriteDesDeuxInterface(jccqddi);
    Tout se passe impec quand je passe dans le constructeur de la variable mcqhddi, le this passé en paramètre de void AddElement (I1* param) a la même adresse que this c'est-à-dire adresse de this = adresse de param.

    Par contre, si j'inverse l'ordre d'implémentation des interfaces dans ma classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ...
    class MaClasseQuiHeriteDesDeuxInterface : public IInutil, public I1
    ...
    alors là dans le constructeur, je me retrouve avec un pointeur this qui est de 4 bits inférieur à la valeur de param. "Olé, c'est super !!!". Donc il doit y avoir un problème de vtbl, mon tableau de pointeur de fonctions virtuelles sur ma classe dépend de l'ordre de déclaration d'implémentation de mes interfaces dans cette classe. Ce qui me paraît plus que bizarre
    Je viens de me repencher sur le bouquin "Mieux développer avec C++" et sur le bouquin de Stroujstrup (excusez pour l'orthographe), rien pas d'indice.
    Donc si vous pouviez m'éclairer et me dire si vous aviez déjà eu ce cas-là.
    Ou bien alors quelque-chose m'échappe et merci de bien vouloir m'éclairer ou alors ... tant pis

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Normal que tu n'aies pas vu ça en Java ou C#, ils ne supportent pas l'héritage multiple. Si tu as une classe C qui hérite de A et de B, Il faut bien stocker les données membre de A et de B quelque part, par exemple en commençant par celles de A, puis celles de B (je ne sais plus si l'ordre est spécifié, mais ça n'y change rien).

    Donc, dans une fonction qui prend un A*, pas de problème, on peut lui passer directement l'adresse de ton C. Pour qu'une fonction qui prend un B* retrouve bien les données qui viennent de B, il faut appliquer un offset à ton C*. C'est cet offset qui doit provoquer le décalage que tu vois. Donc tout va bien.

    Et la gestion de ces offsets est probablement une des raisons pour lesquelles certains implémenteurs de langages ont peur de l'héritage multiple.

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    C'est le cas aussi en java, où l'implémentation d'interfaces multiples évite les problèmes de données du à l'héritage multiple (notamment dans le cas d'héritage en losange).

    Avec les interfaces, la seule donnée dupliquée et le pointeur de vtable, qui est constant et inaccessible à l'utilisateur.

    Mais ça ne change rien au fait qu'une classe qui implémente deux interfaces possède deux pointeurs de vtable. Ils sont donc situés à deux endroits différents de la classe.
    Pour régler le problème, la vtable de la seconde interface ne pointe pas directement sur les fonctions membres, mais sur des "thunk" qui font une soustraction sur le pointeur this avant d'appeler la fonction elle-même.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    731
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 731
    Points : 574
    Points
    574
    Par défaut
    Citation Envoyé par JolyLoic
    Normal que tu n'aies pas vu ça en Java ou C#, ils ne supportent pas l'héritage multiple.
    Euh ... mon exemple montre bien un héritage d'INTRERFACE multiple et non un héritage de CLASSE multiple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Pour régler le problème, la vtable de la seconde interface ne pointe pas directement sur les fonctions membres, mais sur des "thunk" qui font une soustraction sur le pointeur this avant d'appeler la fonction elle-même.
    Tu veux dire par là que si j'ai par exemple une classe CC qui implémente d'abord I1, I2 puis I3 ; si une méthode d'une classe X prend en paramètre un pointeur de I3 et que je passe mon pointeur this de CC à la méthode de la classe X, le this se transformera en this.CC+(offset méthodes virtuelles de I1)+(offset méthodes virtuelles de I2) et donc pointeur au début de la vtbl de l'interface I3 ?

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    731
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 731
    Points : 574
    Points
    574
    Par défaut
    Citation Envoyé par ep31
    Euh ... mon exemple montre bien un héritage d'INTRERFACE multiple et non un héritage de CLASSE multiple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Pour régler le problème, la vtable de la seconde interface ne pointe pas directement sur les fonctions membres, mais sur des "thunk" qui font une soustraction sur le pointeur this avant d'appeler la fonction elle-même.
    Tu veux dire par là que si j'ai par exemple une classe CC qui implémente d'abord I1, I2 puis I3 ; si une méthode d'une classe X prend en paramètre un pointeur de I3 et que je passe mon pointeur this de CC à la méthode de la classe X, le this se transformera en this.CC+(offset méthodes virtuelles de I1)+(offset méthodes virtuelles de I2) et donc pointera au début de la vtbl de l'interface I3 ?

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Pour être précis, ce ne sera pas exactement this qui sera passé, mais this + offset(pointeur vtable I3).
    Typiquement, cet offset est égal à sizeof(classe mère) + sizeof(pointeur vtable I1) + sizeof(pointeur vtable I2).
    C'est-à-dire, sur un système 32bits, sizeof(classe mère) + 8.

    Et la classe aura donc trois ou quatre vtables :
    • vtable pour les fonctions virtuelles de la classe mère.
    • vtable pour I1
    • vtable pour I2
    • vtable pour I3

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    731
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 731
    Points : 574
    Points
    574
    Par défaut
    Ok merci pour tes éclaircissements
    Je vais éviter désormais ralentir l'implémentation de Pattern et les choses trop complexes en C++. Repasser de JAVA à C++, c'est que du bonheur

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Au fait: C'est une des raisons pourquoi il est fortement déconseillé d'utiliser des casts C-style en héritage multiple : Il faut être absolument certain que le cast sera un static_cast et non un reinterpret_cast, car un reinterpret_cast fausserait l'alignement.

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

Discussions similaires

  1. Implémentation d'interface et génériques
    Par jsebfranck dans le forum Langage
    Réponses: 2
    Dernier message: 14/10/2007, 12h54
  2. Réponses: 4
    Dernier message: 02/05/2007, 13h40
  3. Réponses: 5
    Dernier message: 26/07/2006, 17h01
  4. [Language][1.5]Question interfaces multiple:
    Par FreshVic dans le forum Langage
    Réponses: 16
    Dernier message: 18/11/2005, 09h41

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