OVH Cloud OVH Cloud

fonctions virtual

9 réponses
Avatar
Julien Cigar
Bonjour,

Je suis programmeur debutant en C++ et j'en suis aux fonctions virtual.
Je comprends a quoi ca sert, mais je ne vois pas la difference avec la
substitution de fonction.

Par exemple si l'on a une methode virtual crier() dans la classe de
base, qu'est ce que cela apporte de plus que si elle n'etait pas
virtual, puisque la methode crier de la classe derivee prendra quand
meme le dessus sur la fonction de la classe de base ?

Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};

Aussi, avez vous quelques bons sites a me conseiller sur le c++ ?

Merci d'avance.

9 réponses

Avatar
Vincent Richard

Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};


La différence c'est qu'avec ce code :

base* o = new derivee;
o->crier();

- dans le premier cas : c'est crier() de "derivee" qui sera appelée
- dans le second cas : c'est crier() de "base" qui sera appelée

Par contre, avec :

derivee* o = new derivee;
o->crier();

il n'y a aucune différence.

Vincent

--
vmime, une bibliothèque C++ sous licence GPL pour parser et générer
des messages au format MIME : http://www.sourceforge.net/projects/vmime/

Avatar
Jean-Marc Bourguet
Julien Cigar writes:

Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};


base* ptr = new derivee;
ptr->crier() appelle base::crier() dans le second cas, derivee::crier
dans le premier.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Vincent Richard

Donc les classes virtual sont seulement utiles avec les pointeurs ?


Non, ça fonctionne aussi avec les références :

base& b = *new derivee;
b.crier();

Les fonctions virtuelles sont utilisées pour le polymorphisme d'héritage.

PS : ce ne sont pas les classes qui sont virtuelles, mais les fonctions.

Vincent

--
vmime, une bibliothèque C++ sous licence GPL pour parser et générer
des messages au format MIME : http://www.sourceforge.net/projects/vmime/

Avatar
Julien Cigar
Jean-Marc Bourguet wrote:
Julien Cigar writes:


Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};



base* ptr = new derivee;
ptr->crier() appelle base::crier() dans le second cas, derivee::crier
dans le premier.

A+



Donc les classes virtual sont seulement utiles avec les pointeurs ?

Merci.


Avatar
Jean-Marc Bourguet
Julien Cigar writes:

Jean-Marc Bourguet wrote:
Julien Cigar writes:

Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};
base* ptr = new derivee;

ptr->crier() appelle base::crier() dans le second cas, derivee::crier
dans le premier.
A+



Donc les classes virtual sont seulement utiles avec les pointeurs ?


Les classes ne sont pas virtuelles. Les membres -- ou les classes de
base -- peuvent l'etre.

C'est actif des qu'il y a polymorphisme, cad quand le type d'un objet
peut etre different de celui determinable syntaxiquement.

Un autre exemple:

class base {
virtual void f();
void g() { f(); }
}

class d1: public base {
virtual void f();
};

class d2: public base {
virtual void f();
};

d1 o1;
d2 o2;
o1.g();
o2.g();

Lors de l'appel a o1.g(), c'est d1::f() qui est execute, lors de
l'appel a o2.g() c'est d2::f().

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
Jacti

Bonjour,

Je suis programmeur debutant en C++ et j'en suis aux fonctions virtual.
Je comprends a quoi ca sert, mais je ne vois pas la difference avec la
substitution de fonction.

Par exemple si l'on a une methode virtual crier() dans la classe de
base, qu'est ce que cela apporte de plus que si elle n'etait pas
virtual, puisque la methode crier de la classe derivee prendra quand
meme le dessus sur la fonction de la classe de base ?

Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};


Si crier() est déclaré virtuelle dans la classe de base alors tu peux faire

base obj_base;
derivee obj_base_derive;
base* p_base = &obj_base_derivee;

p_base->crier() //appellera crier de derivee car crier() virtuelle dans
base
// et p_base contient l'adreese d'un objet de type derivee

Dans le second cas (crier() non virtuelle), c'est crier() de base qui est
appelé.

Utilité des méthodes virtuelles :
Si tu as plusieurs classes dérivées, tu appelles toujours crier() à partir
d'un pointeur de type base et suivant le type de l'objet pointé (une des
classes dérivées),
c'est la "bonne" méthode crier() qui sera appelée.

Par exemple si tu fais un logiciel de dessin, tu auras une classe de base
"CFigure" et des classes dérivées "CRectangle", "CCercle", etc.

Dans CFigure tu déclareras les méthodes "dessiner", "colorier", etc.
virtuelles
et tu déclareras ton dessin constitué de plusieurs figures comme un tableau

de pointeurs sur CFigure : CFigure* dessin[50];
En supposant que lee éléments du tableau ont été alimentés par des
rectangle, des cercles, etc.
pour dessiner l'ensemble des figure de ton dessin, il suffira que tu fasses

for (i=0;i<50;i++)
dessin[i]->dessiner();
Suivant le type que pointe dessin[i], ça appellera la "bonne"
méthode dessiner.

Ca évite un switch "à la langage C" sur le type de la figure.

J'espère que c'est clair pour toi maintenant.

Cours sur le langage C++ :
http://ltiwww.epfl.ch/Cxx/index.html#c1_2

Jacti

Avatar
Julien Cigar
Jacti wrote:



Bonjour,

Je suis programmeur debutant en C++ et j'en suis aux fonctions virtual.
Je comprends a quoi ca sert, mais je ne vois pas la difference avec la
substitution de fonction.

Par exemple si l'on a une methode virtual crier() dans la classe de
base, qu'est ce que cela apporte de plus que si elle n'etait pas
virtual, puisque la methode crier de la classe derivee prendra quand
meme le dessus sur la fonction de la classe de base ?

Donc quelle est la diff entre : (je mets le minimum pour alleger...)

class base
{
virtual crier();
};

class derivee : public base
{
crier();
};

et

class base
{
crier();
};

class derivee : public base
{
crier();
};



Si crier() est déclaré virtuelle dans la classe de base alors tu peux faire

base obj_base;
derivee obj_base_derive;
base* p_base = &obj_base_derivee;

p_base->crier() //appellera crier de derivee car crier() virtuelle dans
base
// et p_base contient l'adreese d'un objet de type derivee

Dans le second cas (crier() non virtuelle), c'est crier() de base qui est
appelé.

Utilité des méthodes virtuelles :
Si tu as plusieurs classes dérivées, tu appelles toujours crier() à partir
d'un pointeur de type base et suivant le type de l'objet pointé (une des
classes dérivées),
c'est la "bonne" méthode crier() qui sera appelée.

Par exemple si tu fais un logiciel de dessin, tu auras une classe de base
"CFigure" et des classes dérivées "CRectangle", "CCercle", etc.

Dans CFigure tu déclareras les méthodes "dessiner", "colorier", etc.
virtuelles
et tu déclareras ton dessin constitué de plusieurs figures comme un tableau

de pointeurs sur CFigure : CFigure* dessin[50];
En supposant que lee éléments du tableau ont été alimentés par des
rectangle, des cercles, etc.
pour dessiner l'ensemble des figure de ton dessin, il suffira que tu fasses

for (i=0;i<50;i++)
dessin[i]->dessiner();
Suivant le type que pointe dessin[i], ça appellera la "bonne"
méthode dessiner.

Ca évite un switch "à la langage C" sur le type de la figure.

J'espère que c'est clair pour toi maintenant.

Cours sur le langage C++ :
http://ltiwww.epfl.ch/Cxx/index.html#c1_2

Jacti




Merci a tous pour ces explications


Avatar
un.gabacho.sans.pourrier
Julien Cigar a écrit.


Donc les classes virtual sont seulement utiles avec les pointeurs ?



Ouaip. Je suis moi-même une vraie bleusaille. J'ai eu le même problème
que toi, et tout s'est éclairci quand j'ai lu le chapitre sur le cast
dynamique.

Par ailleurs je te conseille ce poly :

http://www.dil.univ-mrs.fr/~garreta/Polys/PolyCpp.html

Ça m'a fait progresser plus en un w.e. qu'en trois semaines...

Avatar
kanze
Julien Cigar wrote in message
news:<3fa101ce$0$1114$...

[...]

base* ptr = new derivee;
ptr->crier() appelle base::crier() dans le second cas,
derivee::crier dans le premier.


Donc les classes virtual sont seulement utiles avec les pointeurs ?


Ce ne sont pas les classes qui sont virtuelles, mais les fonctions.

Et ça marche aussi avec des références, ou lors des appels à l'intérieur
d'une fonction membre (qui sont implicitement avec le pointeur this).

Formellement, la virtualité est toujours en cause. Pratiquement, si le
compilateur connaît le type dynamique, il optimise l'appel. Si
l'expression à gauche du point est le nom d'une variable, ou correspond
à un temporaire, ou si l'appel est direct depuis un constructeur, le
compilateur en connaît le type dynamique à tous les coups ; je ne
connais pas de compilateur qui n'optimise pas dans ce cas-là. Au délà,
ça dépend un peu de l'analyse que sait faire le compilateur, mais j'ai
comme une impression qu'ils ne le poussent pas très loin.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16