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.
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.
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Franck Branjonneau
Olivier Miakinen <om+ écrivait:
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 ?
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
Olivier Miakinen <om+news@miakinen.net> écrivait:
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 ?
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 {};
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 ?
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
Olivier Miakinen
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.
**** 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.
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 ?
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.
**** 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.
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 ?
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.
**** 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.
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 ?
Michel Decima
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:
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.
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:
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).
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:
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.
Olivier Miakinen
[...]
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.
[...]
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.
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.