Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Héritage et fonction virtuelle

5 réponses
Avatar
PurL
Bonjour,

Pouvez-vous me dire quel comportement y'a t-il entre ces 2 déclarations :

1/

class A
{
...
virtual void fct() = 0;
...
};

class B : public A
{
...
virtual void fct() = 0;
...
};

class C : public B
{
...
void fct() { //code}
...
};

et :

2/
class A
{
...
virtual void fct() = 0;
...
};

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

class C : public B
{
...
void fct() { //code}
...
};

La différence est que fct n'est pas redéfinie au sein de B.

Merci,

PurL

5 réponses

Avatar
Loïc Joly
PurL wrote:
Bonjour,

Pouvez-vous me dire quel comportement y'a t-il entre ces 2 déclarations :

1/

class A
{
...
virtual void fct() = 0;
...
};

class B : public A
{
...
virtual void fct() = 0;
...
};

class C : public B
{
...
void fct() { //code}
...
};



Dans ce cas, la fonction B::fct peut être définie (le =0 n'empêche pas
ça). Exemple où ça peut servir : fct est une fonction "en cascade",
genre save, c'est à dire que la fonction de la classe dérivée doit
commencer par appeler la version de la classe de base. Quand on écrit B,
classe abstraite pour d'autres raisons, on a quand même besoin d'écrire
la fonction B::save pour sauver les données correspondant à B. Et on n'a
pas envie que les gens qui dérivent de B oublient de définir une
fonction save à eux. Donc on déclare B::save virtuelle pure, et on la
défini quand même (remarque : Souvent, dans ce genre de cas, la fonction
est protected).

--
Loïc

Avatar
Jean-Marc Bourguet
"PurL" writes:

Bonjour,

Pouvez-vous me dire quel comportement y'a t-il entre ces 2 déclarations :

1/

class A
{
...
virtual void fct() = 0;
...
};

class B : public A
{
...
virtual void fct() = 0;
...
};
2/

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

La différence est que fct n'est pas redéfinie au sein de B.


Outre la possibilite de definir fct (voir message de Loïc), il me
semble que ca peut changer la recherche des noms; si fct est surcharge
dans B, un appel a travers un B ne trouvera pas void fct() venant de A
sans la declaration.

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
PurL
Dans ce cas, la fonction B::fct peut être définie (le =0 n'empêche pas
ça). Exemple où ça peut servir : fct est une fonction "en cascade",
genre save, c'est à dire que la fonction de la classe dérivée doit
commencer par appeler la version de la classe de base. Quand on écrit
B, classe abstraite pour d'autres raisons, on a quand même besoin
d'écrire la fonction B::save pour sauver les données correspondant à
B. Et on n'a pas envie que les gens qui dérivent de B oublient de
définir une fonction save à eux. Donc on déclare B::save virtuelle
pure, et on la défini quand même (remarque : Souvent, dans ce genre
de cas, la fonction est protected).


Je suis d'accord, c'est meme l'effet désirée (cascade) sauf que je n'ai pas
besoin ne redéfinir la fct de B. Je voulais juste savoir ce que cela
changeait pour A.
Si j'ai bien compris, qu'il y ait la déclaration virtual void fct() = 0;
dans B ou pas, ne change rien pour A ?
J'avais un doute dans le fait de ne pas déclarer fct dans B de "casser" la
chaine de l'héritage...

pouvez-vous confirmer ?

Merci,

PurL

Avatar
Alexandre
Si j'ai bien compris, qu'il y ait la déclaration virtual void fct() = 0;
dans B ou pas, ne change rien pour A ?


oui.

J'avais un doute dans le fait de ne pas déclarer fct dans B de "casser" la
chaine de l'héritage...


non, n'étant pas redéclarée, la version de A est utilisée, donc la fonction
est présente mais en virtuelle pure.


pouvez-vous confirmer ?

Merci,

PurL




Avatar
drkm
Jean-Marc Bourguet writes:

"PurL" writes:

1/

class A
{
virtual void fct() = 0;
};

class B : public A
{
virtual void fct() = 0;
};


2/
class B : public A
{
};

La différence est que fct n'est pas redéfinie au sein de B.


Outre la possibilite de definir fct (voir message de Loïc), il me
semble que ca peut changer la recherche des noms; si fct est surcharge
dans B, un appel a travers un B ne trouvera pas void fct() venant de A
sans la declaration.


J'ai du mal à comprendre ce que tu veux dire. En tout cas, ceci
fonctionne comme prévu :

~> cat fclcxx.cc
#include <iostream>
#include <ostream>

struct A {
virtual void fct() = 0 ;
} ;
struct B : A {
virtual void fct() = 0 ;
} ;
struct C : B {
void fct() {
std::cout << "C::fct()" << std::endl ;
}
} ;

struct X {
virtual void fct() = 0 ;
} ;
struct Y : X {
} ;
struct Z : Y {
void fct() {
std::cout << "Z::fct()" << std::endl ;
}
} ;

int main() {
B * b = new C() ;
Y * y = new Z() ;
b->fct() ;
y->fct() ;
}
~> g++ -o fclcxx fclcxx.cc -Wall -ansi -pedantic
~> ./fclcxx
C::fct()
Z::fct()

--drkm