C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[long][C++ Windows] Probleme de transtypage

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Olivier Miakinen
Guest





PostPosted: Thu Apr 12, 2007 11:14 pm    Post subject: [long][C++ Windows] Probleme de transtypage Reply with quote



Bonjour,

Je suis en train de faire le portage sur Visual Studio 2005 (ou Visual
Studio 8.0, il me semble que c'est la même chose) d'un immense projet
qui fonctionnait avec Visual C++ 98 (ou Visual C++ 6.0). Je tombe en
particulier sur un bout de code qui me semble assez laid mais qui ne
plantait pas et qui plante maintenant, et j'aimerais savoir ce que je
dois modifier pour qu'il retombe en marche.

Ce code met en œuvre pas moins de 7 classes différentes, que pour
simplifier je renomme ici A, B, C, D, E, F et G. Les déclarations
sont les suivantes.

class A : public B, C
{ ... };

class B : public D, public E
{ ... };

class C
{ ... };

class D : public F
{ ... };

class E
{ ... };

class F : public G
{ ... };

J'ai tout mis pour être le plus précis possible, mais je suppose que
le problème (que je n'ai pas encore exposé) serait le même avec la
simple déclaration suivante.

class A : public G, C
{ ... };

Dans A, il y a une méthode A::une_methode qui appelle la fonction
une_fonction en lui passant le paramètre this.

A::une_methode()
{
...
une_fonction(this);
...
}

La fonction une_fonction est la suivante.

une_fonction(C *pc)
{
...
G *pg = dynamic_cast<G *>(pc);
...
}

**** LE PROBLÈME ****

Le problème est que pc est non nul, mais que pg est nul. Pourtant, le
débugueur m'indique que pc est bien un pointeur vers un objet de type A,
et A hérite bien d'un (et un seul) objet de type G.

Que puis-je faire ? Je précise que j'ai le droit de modifier les
déclarations et définitions des premières classes, en particulier
A, B et C, et aussi de A::une_methode et de une_fonction.

Par exemple, est-ce que déclarer que C hérite aussi de G résoudrait le
problème ? Il faudrait bien sûr qu'il y ait un seul G au final dans A,
mais je ne sais pas comment déclarer cela.

Cordialement,
--
Olivier Miakinen
Back to top
Franck Branjonneau
Guest





PostPosted: Fri Apr 13, 2007 1:03 am    Post subject: Re: [long][C++ Windows] Probleme de transtypage Reply with quote



Olivier Miakinen <om+news (AT) miakinen (DOT) net> écrivait:

Quote:
J'ai tout mis pour être le plus précis possible, mais je suppose que
le problème (que je n'ai pas encore exposé) serait le même avec la
simple déclaration suivante.

class A : public G, C
{ ... };

[ Code équivalent à

A a;
C * pc(&a);
G * pg(dynamic_cast< G * >(pc));

]

**** LE PROBLÈME ****

Le problème est que pc est non nul, mais que pg est nul.

G et C sont-ils polymorphes ?

Quote:
Pourtant, le débugueur m'indique que pc est bien un pointeur vers un objet
de type A, et A hérite bien d'un (et un seul) objet de type G.

Par exemple, est-ce que déclarer que C hérite aussi de G résoudrait le
problème ? Il faudrait bien sûr qu'il y ait un seul G au final dans A,
mais je ne sais pas comment déclarer cela.

L'héritage en diamant c'est :

class Base { public: virtual ~Base(); };

class Left: public virtual Base {};
class Right: public virtual Base {};

class Derived: public Left, public Right {};

Derived "a" une unique Base.

--
Franck Branjonneau
Back to top
Olivier Miakinen
Guest





PostPosted: Fri Apr 13, 2007 2:55 am    Post subject: Re: [long][C++ Windows] Probleme de transtypage Reply with quote



Le 12/04/2007 22:03, Franck Branjonneau a écrit :
Quote:

J'ai tout mis pour être le plus précis possible, mais je suppose que
le problème (que je n'ai pas encore exposé) serait le même avec la
simple déclaration suivante.

class A : public G, C
{ ... };

[ Code équivalent à

A a;
C * pc(&a);
G * pg(dynamic_cast< G * >(pc));

]

Oui, en effet.

Quote:
**** LE PROBLÈME ****

Le problème est que pc est non nul, mais que pg est nul.

G et C sont-ils polymorphes ?

Je dois le vérifier, mais j'espère que oui. Si ce n'est pas le cas pour
C cela peut s'arranger facilement. Malheureusement, si ce n'est pas le
cas pour les classes D, F, G je ne pourrai rien y faire : il s'agit de
classes fournies par les MFC de Microsoft, la dernière étant CWnd.

Je regarde ça demain, de retour sur mon lieu de travail.

Quote:
Par exemple, est-ce que déclarer que C hérite aussi de G résoudrait le
problème ? Il faudrait bien sûr qu'il y ait un seul G au final dans A,
mais je ne sais pas comment déclarer cela.

L'héritage en diamant c'est :

class Base { public: virtual ~Base(); };

class Left: public virtual Base {};
class Right: public virtual Base {};

class Derived: public Left, public Right {};

Derived "a" une unique Base.

Et si à la place de Left j'ai une chaîne de classes Left1, Left2, Left3,
toutes doivent être polymorphes ? Est-ce que le « virtual » dans la
déclaration de l'héritage est obligatoire aussi ? Si oui, c'est perdu :
j'ai écrit les déclarations telles qu'elles sont, et je ne peux rien
faire pour changer les classes des MFC.

Cela dit, comment expliquer que le transtypage fonctionnait en VC++ 6.0
et ne fonctionne plus en Visual Studio 8.0 ?
Back to top
Olivier Miakinen
Guest





PostPosted: Fri Apr 13, 2007 9:12 am    Post subject: Re: [long][C++ Windows] Probleme de transtypage Reply with quote

Le 13/04/2007 09:49, Michel Decima a écrit :
Quote:

[...]

Juste pour faire taire le warning, je change la declaration de A qui va
maintenant deriver en public de C:

[...]

Suite a la modification, xlC produit une valeur nulle en mode par
defaut, mais non nulle en mode standard. Pour g++, on a une valeur non
nulle dans les deux cas.

Bon, je n'explique pas la situation, mais il y aurait peut etre une
solution a ton probleme si tu peux passer la derivation de C en public
(dans le cas bien sur ou l'absence de mot-cle dans le code d'origine
n'est pas une coquille).

L'absence du mot-clé « public » dans le code d'origine n'était pas une
coquille de ma part. Je viens de le rajouter, et en effet ça fonctionne
parfaitement maintenant !

Je suis toujours intéressé par une explication si quelqu'un en a une,
mais au moins je peux continuer à avancer sur le reste. Un grand merci
pour cela.
Back to top
Michel Decima
Guest





PostPosted: Fri Apr 13, 2007 9:12 am    Post subject: Re: [long][C++ Windows] Probleme de transtypage Reply with quote

Olivier Miakinen a écrit :
Quote:
Le 12/04/2007 22:03, Franck Branjonneau a écrit :

Cela dit, comment expliquer que le transtypage fonctionnait en VC++ 6.0
et ne fonctionne plus en Visual Studio 8.0 ?

J'ai essaye le code suivant, qui correspond a la version simplifiee avec
trois classes seulement, sur les compilateurs que j'ai a disposition ici
(xlC-6 et g++-4.1) :

#include <iostream>

class G {
public:
virtual ~G() {}
};

class C {
public:
virtual ~C() {}
};

class A : public G, C {
public:
void une_methode();
};

void une_fonction(C *pc)
{
G *pg = dynamic_cast<G *>(pc);
std::cout << pc << " " << pg << std::endl;
}

void A::une_methode() {
une_fonction( this );
}

int main() {
A a;
a.une_methode();
}

Ce programme me donne toujours une valeur nulle pour pg:

$ xlC transtypage.cpp && ./a.out
2ff21fb4 0

$ xlC -qlanglvl=strict98 transtypage.cpp && ./a.out
2ff21fb4 0

$ g++ transtypage.cpp && ./a.out
0x2ff21fa4 0

$ g++ -std=c++98 transtypage.cpp && ./a.out
0x2ff21fa4 0

Element interessant, xlC me signale que la classe A dérive de manière
privée de C, puisque c'est le comportement par défaut quand on ne
precise rien:

"transtypage.cpp", line 13.22: 1540-0198 (W) The omitted keyword
"private" is assumed for base class "C".

Juste pour faire taire le warning, je change la declaration de A qui va
maintenant deriver en public de C:

class A : public G, public C {
public:
void une_methode();
};

Et les tests donnent:

$ xlC transtypage.cpp && ./a.out
2ff21fa4 0

$ xlC -qlanglvl=strict98 transtypage.cpp && ./a.out
2ff21fa4 2ff21fa0

$ g++ transtypage.cpp && ./a.out
0x2ff21f94 0x2ff21f90

$ g++ -std=c++98 transtypage.cpp && ./a.out
0x2ff21f94 0x2ff21f90

Suite a la modification, xlC produit une valeur nulle en mode par
defaut, mais non nulle en mode standard. Pour g++, on a une valeur non
nulle dans les deux cas.

Bon, je n'explique pas la situation, mais il y aurait peut etre une
solution a ton probleme si tu peux passer la derivation de C en public
(dans le cas bien sur ou l'absence de mot-cle dans le code d'origine
n'est pas une coquille).

MD.
Back to top
James Kanze
Guest





PostPosted: Fri Apr 13, 2007 9:12 am    Post subject: Re: [C++ Windows] Probleme de transtypage Reply with quote

On Apr 13, 10:14 am, Olivier Miakinen <om+n...@miakinen.net> wrote:
Quote:
Le 13/04/2007 09:49, Michel Decima a écrit :
[...]

Juste pour faire taire le warning, je change la declaration de A qui va
maintenant deriver en public de C:

[...]

Suite a la modification, xlC produit une valeur nulle en mode par
defaut, mais non nulle en mode standard. Pour g++, on a une valeur non
nulle dans les deux cas.

Bon, je n'explique pas la situation, mais il y aurait peut etre une
solution a ton probleme si tu peux passer la derivation de C en public
(dans le cas bien sur ou l'absence de mot-cle dans le code d'origine
n'est pas une coquille).

L'absence du mot-clé « public » dans le code d'origine n'était pas une
coquille de ma part. Je viens de le rajouter, et en effet ça fonctionne
parfaitement maintenant !

Je suis toujours intéressé par une explication si quelqu'un en a une,
mais au moins je peux continuer à avancer sur le reste. Un grand merci
pour cela.

L'explication est simple : dynamic_cast ne permet pas de
naviguer à travers des héritages privés (ni protégés), et que
VC++ 6.0 avait un bogue, et ne vérifiait pas l'accès.

Pour cité la norme (en ce qui concerne l'expression
« dynamic_cast< T >( v ) », après la discussion d'un certain
nombre de vérifications préliminaires) :

The run-time check logically executes as follows:

-- If, in the most derived object pointed (referred) to by
v, v points (refers) to a public base class subobject of
a T object, and if only one object of type T is derived
from the subobject pointed (referred) to by v the result
is a pointer (an lvalue referring) to that T object.

-- Otherwise, if v points (refers) to a public base class
subobject of the most derived object, and the type of
the most derived object has a base class, of type T,
that is unambiguous and public, the result is a pointer
(an lvalue referring) to the T subobject of the most
derived object.

-- Otherwise, the run-time check fails.

Avec l'héritage public, ton code tombe dans le deuxième cas
ci-dessus. Avec l'héritage privé, non, et il finit dans le
troisième cas.

--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Olivier Miakinen
Guest





PostPosted: Fri Apr 13, 2007 2:27 pm    Post subject: Re: [C++ Windows] Probleme de transtypage Reply with quote

Le 13/04/2007 11:08, James Kanze a écrit :
Quote:

L'explication est simple : dynamic_cast ne permet pas de
naviguer à travers des héritages privés (ni protégés), et que
VC++ 6.0 avait un bogue, et ne vérifiait pas l'accès.

Pour cité la norme (en ce qui concerne l'expression
« dynamic_cast< T >( v ) », après la discussion d'un certain
nombre de vérifications préliminaires) :

The run-time check logically executes as follows:

-- [...]

-- Otherwise, if v points (refers) to a public base class
subobject of the most derived object, and the type of
the most derived object has a base class, of type T,
that is unambiguous and public, the result is a pointer
(an lvalue referring) to the T subobject of the most
derived object.

Ouf ! C'est drôlement dur à lire, mais je crois avoir compris. Je
m'attendais bien à l'exigence d'avoir une classe de type T « that
is unambiguous and *public* » mais je ne pensais pas que v devait
forcément pointer vers un « *public* base class subobject ».

Quote:
-- Otherwise, the run-time check fails.

Avec l'héritage public, ton code tombe dans le deuxième cas
ci-dessus. Avec l'héritage privé, non, et il finit dans le
troisième cas.

Bon, eh bien c'est finalement très clair grâce à toi. Maintenant
je tombe sur un autre problème, mais celui-ci concerne encore plus
étroitement les classes MFC de Microsoft plutôt que le C++ alors
je ne vous embêterai pas avec ça.
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.