Appel de méthode avec héritage

guillaumech

Expert
Bonjour à tous,

Je vais certainement me faire taper sur les doigts, mais bon, je me souviens comment faire ceci (en C++) :

[cpp]
class A {
public :
void Fct();
}

class B : A{
public :
void Fct();
}
[/cpp]

[cpp]
...
list<A> liste;
list.push_back(new B());
(liste.First()).Fct() <--------- /!\
[/cpp]

J'aimerai qu'au point d'exclamation, ce soit la méthode de B qui soit appelé... Moi qui pensais que c'était comme ça qu'on faisait, mais ça n'a pas l'aire de bien marcher.
Merci pour votre aide ;)
 

guillaumech

Expert
:( Personne pour m'aider ...
J'ai un peux tout essayé, avec des virtual, des méthodes pures ... mais je n'arrive pas à atteindre la méthode Fct() de B dans une collection de A, alors que dans cette collection, des objets B y sont bien insérés ...
Même le grand Zeb à oublié le C++ :p
 

zeb

Modérateur
Salut mon guich, :hello:
Alors t'es tout perdu en C++ :(

Code:
list<A> liste;
Donc c'est du A. Pas du B.
B surclassse A. Ok. Mais la fonction A.Fct() n'est pas virtuelle, donc elle est redéfinie et non pas surchargée par B.Fct().
 

guillaumech

Expert
Ok, je croyais que j'avais déjà essayé ...
Donc je met Fct() de A en virtuel, sans la définir dans son cpp et pour Fct() de B je touche rien, avec sa définition dans le cpp. Et ça devrait marcher ?
Merci Zeb, j'espère que ça va roxer, mais je crois avoir déjà essayé en vain, mais bon, je vais retenter ce soir.
 

zeb

Modérateur
Tu peux la définir, mais il faut la mettre en virtuelle.
Si tu la mets en virtuelle et ne la définie pas, elle sera virtuelle pure, ce qui n'est pas la même chose :o
 

guillaumech

Expert
Ha bon ??? Ralalal, j'ai de vieilles lacunes :'(
Pour moi virtuelle pure c'était (seulement) avec le mot clé virtual ET = 0 à la définition ...
Mais oui, je ne souhaite pas que la class A soit abstraite ;)
 

zeb

Modérateur
Fonction virtuelle, virtuelle pure, classe abstraite... t'as de beaux restes quand même :lol:
 

batchy

Grand Maître
[cpp]
...
list<A> liste;
list.push_back(new B());
(liste.First()).Fct() <--------- /!\[/cpp]

J'arrive déjà pas à comprendre comment ça peut compiler. Ah ben non, ça compile pas.
Code:
fuck.c++:12: erreur: no matching function for call to ‘std::list<A, std::allocator<A> >::push_back(B*)’
/usr/include/c++/4.4/bits/stl_list.h:919: note: candidats sont: void std::list<A, std::allocator<A> >::push_back(const A&)

Quand on met un A dans une list, de même que lorsqu'on définit une variable A, il ne peut y avoir que un A dedans. en C++, les A sont forcement des A. mais des A* peuvent être des B*, tout comme des A& peuvent aussi être des B& (mais on peut pas mettre de A& dans une liste).

Et c'est lorsque tu manipule un A* que les artifices de méthodes virtuelles apparaissent. Si tu manipule un A* qui contient un B*, et que tu utilise une méthode non-virtuelle de A, alors c'est la méthode de A qui sera appelée. mais si ta méthode est virtuelle, alors c'est la méthode de B qui sera appelée.
 

guillaumech

Expert
Impec Batchy, mais j'ai un autre soucis alors :pfff:

[cpp]
class A {
private :
(...)
public :
(...)
virtual void Extraction ();
};
[/cpp]

[cpp]
class B : public A {
public :
(...)
void Extraction ();
(...)
~B();
};
[/cpp]


[cpp]
list<DataLine*> dataLines = (*itorParams).RetourneDataLines();
list<DataLine*>::iterator itorDL = dataLines.begin();
while (itorDL != dataLines.end()) {
(*itorDL)->Extraction();
itorDL++;
}
[/cpp]
Le (*itorDL)->Extraction(); me met en erreur de seg :(

Ma liste dataLines est remplie comme ça :
[cpp]
B b("...", ".....");
mDataLines.push_back (&b);
[/cpp]

Merci en tout cas Batchy, j'ai un peux avancé :)
 

batchy

Grand Maître
ton B est allouée sur la pile. quand ta fonction sera terminée, ton B partira a la poubelle, et le pointeur que tu aura stocké dans mDataLines pointera vers n'importe quoi.

avec B* pb= new B("...", "....."); ça devrait aller mieux
 

guillaumech

Expert
[cpp]
B *b = new B(".....", ".......");
mDataLines.push_back (b);
[/cpp]
Après je fais :
[cpp]
list<A*> dataLines = (*itorParams).RetourneDataLines();
list<A*>::iterator itorDL = dataLines.begin();
while (itorDL != dataLines.end()) {
(*itorDL)->Extraction(); // Appel Extraction() de A ...
itorDL++;
}
[/cpp]
Le RetourneDataLines() renvoi mDataLines remplie au dessus. Et l'appel de la méthode Extraction() appel celle de A et non celle de B ...
Alors que je suis dans ce cas de figure :
[cpp]
class B : public A {
public :
B (std::string _ligne, std::string _champ);
void Extraction ();
~Temperature();
};

class A {
private :
public :
A (std::string _ligne, std::string _champ);
virtual void Extraction ();
};
[/cpp]

Rahh, on va y arrive Batchy :) lol En tout cas j'ai plus l'erreur de seg ;)
Merci
 

batchy

Grand Maître
Normalement ça devrai marcher ...

que fait A::Extraction() et Temperature::Extraction() ?
 

guillaumech

Expert
Je te remets le code avec les bons noms de méthodes :

[cpp]
class DataLine {
private :
std::string mLigne;
public :
std::string mChamp;

DataLine (std::string _ligne, std::string _champ);
virtual void Extraction ();
void Coloration ();
void Isolignes ();
void SQL ();
void Valeurs ();
};
[/cpp]

[cpp]
void DataLine::Extraction () {
cout << "Extraction DataLine" << endl;
}
[/cpp]

[cpp]
class Temperature : public DataLine {
public :
Temperature (std::string _ligne, std::string _champ);
void Extraction ();
void Coloration ();
void Isolignes ();
void SQL ();
void Valeurs ();
~Temperature();
};
[/cpp]

[cpp]
void Temperature::Extraction () {
cout << "Extraction temperature" << endl;
}
[/cpp]

[cpp]
int main (int argc, char* argv[])
{
DataLine::Extraction();
getchar();
Temperature::Extraction();

return 0;
}
[/cpp]

Erreurs :
[cpp]
main.cpp: In function ‘int main(int, char**)’:
main.cpp:18: error: cannot call member function ‘virtual void DataLine::Extraction()’ without object
main.cpp:20: error: cannot call member function ‘virtual void Temperature::Extraction()’ without object
[/cpp]

Merci Batch(y) :)
 

batchy

Grand Maître
quand je disait "que fait DataLine::Extraction()", je voulais juste le corps de la méthode.

si tu écrit DataLine::Extraction(), il te dit qu'il n'a pas d'instance et il est pas content ;)

Est tu sur que dataLines (la std::list) n'est pas vide ?
 

guillaumech

Expert
Oui, la liste n'est pas vide (size() égal à 1), regarde les messages au dessus pour voir comment je la rempli (si c'est correct) :

Code :

1. B *b = new B(".....", "......." );
2. mDataLines.push_back (b);


Après je fais :
Code :

1. list<A*> dataLines = (*itorParams).RetourneDataLines();
2. list<A*>::iterator itorDL = dataLines.begin();
3. while (itorDL != dataLines.end()) {
4. (*itorDL)->Extraction(); --------------------------------------/!\
5. itorDL++;
6. }

Au /!\, il appel la méthode de DataLine, il affiche donc : Extraction DataLine, au lieu d'appeller la méthode de Temperature ! :(
 

batchy

Grand Maître
À mon avis, y a un problème, et dès que tu va utiliser les données de B, ça va planter.

Utilise valgrind sur ton programme.
Code:
valgrind  --track-origins=yes ./a.out
lui il te trouvera l'erreur ;)
 

guillaumech

Expert
L'option --track-origins=yes ne fonctionne pas chez moi. Mais voici le code de retour avec un simple valgrind ./exe (j'ai l'impression qu'il n'y a pas tellement d'erreur)

[cpp]
==29635== Memcheck, a memory error detector.
==29635== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==29635== Using LibVEX rev 1854, a library for dynamic binary translation.
==29635== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==29635== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation framework.
==29635== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==29635== For more details, rerun with: -v
==29635==
ext

Extraction DataLine
==29635==
==29635== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 1)
==29635== malloc/free: in use at exit: 118 bytes in 6 blocks.
==29635== malloc/free: 27 allocs, 21 frees, 490 bytes allocated.
==29635== For counts of detected errors, rerun with: -v
==29635== searching for pointers to 6 not-freed blocks.
==29635== checked 113,276 bytes.
==29635==
==29635== LEAK SUMMARY:
==29635== definitely lost: 118 bytes in 6 blocks.
==29635== possibly lost: 0 bytes in 0 blocks.
==29635== still reachable: 0 bytes in 0 blocks.
==29635== suppressed: 0 bytes in 0 blocks.
==29635== Rerun with --leak-check=full to see details of leaked memory.
[/cpp]

Je t'ai mis tout le code Batchy, je te donnerai bien les sources entières, mais je ne suis pas sûr que ça t'avance tant que ça. Ca m'appelle toujours la méthode de Extraction() de DataLines, alors que l'objet est un Temperature :(
 

batchy

Grand Maître
bien sur que si les sources entières m'avanceraient : ça me permet de les exécuter et de les gdb moi-même.
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 129
Messages
6 717 853
Membres
1 586 373
Dernier membre
https://forum.tomshardwar
Partager cette page
Haut