OVH Cloud OVH Cloud

Fonctions virtuelles ''globalement pures''

17 réponses
Avatar
Fabien LE LEZ
Bonjour,

Soit la classe :

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

enum Couleur { ROUGE, VERT };
virtual void f (Couleur couleur)
{
switch (couleur)
{
case ROUGE: f_Rouge(); break;
case VERT: f_Vert(); break;
};
}
virtual void f_Rouge() { f (ROUGE); }
virtual void f_Vert() { f (VERT); }
};

Les fonctions de cette classe sont "globalement virtuelles pures",
i.e. pour que ça marche, une classe dérivée doit redéfinir soit f(),
soit f_Rouge() et f_Vert().

Y a-t-il un moyen de tester cela à la compilation ?

Merci d'avance...

10 réponses

1 2
Avatar
Rémy
"Fabien LE LEZ" a écrit dans le message de news:

Bonjour,

Soit la classe :

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

enum Couleur { ROUGE, VERT };
virtual void f (Couleur couleur)
{
switch (couleur)
{
case ROUGE: f_Rouge(); break;
case VERT: f_Vert(); break;
};
}
virtual void f_Rouge() { f (ROUGE); }
virtual void f_Vert() { f (VERT); }
};

Les fonctions de cette classe sont "globalement virtuelles pures",
i.e. pour que ça marche, une classe dérivée doit redéfinir soit f(),
soit f_Rouge() et f_Vert().



Ca "marche" tel quel.
Evidemment le programme utilisant l'une de ces fonctions va planter à cause
d'une récursion infinie, mais ce n'est pas un problème lié à la virtualité
des fonctions, uniquement un problème de design.

C'est comme si j'écrivais :

virtual void f()
{
int x = 2/0;
}

Et que je dise :
Pour que "ca marche", il faut redéfinir f.

En fait, ma fonction f plante à l'exécution et si on la redéfinit
(correctement), le programme l'utilisant ne plante plus, mais ça n'a rien à
voir avec la notion de virtuelle pure.

Y a-t-il un moyen de tester cela à la compilation ?

Merci d'avance...


A mon avis non.

Cordialement

Rémy

Avatar
Fabien LE LEZ
On Mon, 12 Jun 2006 11:12:10 +0200, "Rémy" :

Et que je dise :
Pour que "ca marche", il faut redéfinir f.


Yep, mais dans ce cas, il suffit de la définir virtuelle pure.

Avatar
Marc Duflot
Fabien LE LEZ wrote:
Bonjour,

Soit la classe :

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

enum Couleur { ROUGE, VERT };
virtual void f (Couleur couleur)
{
switch (couleur)
{
case ROUGE: f_Rouge(); break;
case VERT: f_Vert(); break;
};
}
virtual void f_Rouge() { f (ROUGE); }
virtual void f_Vert() { f (VERT); }
};

Les fonctions de cette classe sont "globalement virtuelles pures",
i.e. pour que ça marche, une classe dérivée doit redéfinir soit f(),
soit f_Rouge() et f_Vert().

Y a-t-il un moyen de tester cela à la compilation ?


Avec deux classes intermédiaires dont les classes concrètes dérivent ?

class C
{
public:
virtual ~C(){}
virtual void f (Couleur couleur) = 0;
virtual void f_Rouge() =0;
virtual void f_Vert() =0;
};

class C1 : public C
{
public:
virtual void f (Couleur couleur)
{
switch (couleur)
{
case ROUGE: f_Rouge(); break;
case VERT: f_Vert(); break;
};
}
};

class C2 : public C
{
public:
virtual void f_Rouge() { f (ROUGE); }
virtual void f_Vert() { f (VERT); }
};

Avatar
Rémy
"Fabien LE LEZ" a écrit dans le message de news:

On Mon, 12 Jun 2006 11:12:10 +0200, "Rémy" :

Et que je dise :
Pour que "ca marche", il faut redéfinir f.


Yep, mais dans ce cas, il suffit de la définir virtuelle pure.




Pour obtenir le comportement que tu souhaites, oui.

Mais à mon avis, le compilateur n'a pas plus les informations nécessaires
pour le détecter.

Je n'imagine pas comment le compilateur pourrait "savoir" en compilant une
classe D héritant de C que certaines méthodes doivent être redéfinies, alors
que justement la classe C en fournit une implémentation.

On pourrait rajouter dans C une méthode virtuelle pure
virtual void Avez_vous_pense_a_redefinir_f_ou_f_Rouge_et_f_Vert() = NULL;

Mais ce ne serait qu'un pense bête pour les utilisateurs.


Cordialement

Rémy


Avatar
Sylvain
Fabien LE LEZ wrote on 12/06/2006 11:00:

Les fonctions de cette classe sont "globalement virtuelles pures",
i.e. pour que ça marche, une classe dérivée doit redéfinir soit f(),
soit f_Rouge() et f_Vert().


la virtualité ne sert pas à faire en sorte que "cela marche" (cette fin
n'est pas exclue d'un design reposant sur la virtualité).

elle sert à -prevenir l'instantiation d'une classe si une des méthodes
est pure, -à prévenir l'accès à la méthode d'une classe parent pour une
méthode surchargé.

l'expression globalement pures est donc abusive, la classe présentée est
simplement globalement inutilisable mais parfaitement compilable et
instantiable - seul un "avez-vous-pensez..." tel qu'introduit par Rémy
évitera les cata ... si l'utilisateur joue complètement le jeu (j'ai du
mal à dire respecter le contrat ici).

Sylvain.

Avatar
Fabien LE LEZ
On Mon, 12 Jun 2006 11:36:41 +0200, Marc Duflot :

Avec deux classes intermédiaires dont les classes concrètes dérivent ?


Effectivement, ça m'a l'air d'être la solution.
J'hésite entre la suspicion (Y aurait-il, dans cette solution, un
détail bloquant qui nous aurait échappé ?) et la honte de n'y avoir
pas pensé moi-même.

Avatar
Rémy
"Fabien LE LEZ" a écrit dans le message de news:

On Mon, 12 Jun 2006 11:36:41 +0200, Marc Duflot :

Avec deux classes intermédiaires dont les classes concrètes dérivent ?


Effectivement, ça m'a l'air d'être la solution.
J'hésite entre la suspicion (Y aurait-il, dans cette solution, un
détail bloquant qui nous aurait échappé ?) et la honte de n'y avoir
pas pensé moi-même.




Eh bien, ça suppose que l'utilisateur sait dans chaque cas de quelle classe
il doit hériter (C1 ou C2) selon ce qu'il veut faire.

Par ailleurs, rien n'interdit d'hériter de C1 et C2, ce qui donne un code
compilable...

class D : public C1, public C2
{
};


Rémy


Avatar
Rémy
"Rémy" a écrit dans le message de news:
e6jfq9$87b$

"Fabien LE LEZ" a écrit dans le message de news:

On Mon, 12 Jun 2006 11:36:41 +0200, Marc Duflot :

Avec deux classes intermédiaires dont les classes concrètes dérivent ?


Effectivement, ça m'a l'air d'être la solution.
J'hésite entre la suspicion (Y aurait-il, dans cette solution, un
détail bloquant qui nous aurait échappé ?) et la honte de n'y avoir
pas pensé moi-même.




Eh bien, ça suppose que l'utilisateur sait dans chaque cas de quelle
classe il doit hériter (C1 ou C2) selon ce qu'il veut faire.

Par ailleurs, rien n'interdit d'hériter de C1 et C2, ce qui donne un code
compilable...

class D : public C1, public C2
{
};


Rémy



Oups, j'ai écrit une bêtise, ma classe D compile mais est toujours virtuelle
pure...

Rémy



Avatar
Sylvain
Rémy wrote on 12/06/2006 12:48:

Oups, j'ai écrit une bêtise, ma classe D compile mais est toujours virtuelle
pure...

parce que C1 et C2 n'hérite pas virtuellement de C ?


Sylvain.

Avatar
Rémy
"Sylvain" a écrit dans le message de news:
448d4754$0$833$
Rémy wrote on 12/06/2006 12:48:

Oups, j'ai écrit une bêtise, ma classe D compile mais est toujours
virtuelle pure...

parce que C1 et C2 n'hérite pas virtuellement de C ?


Sylvain.



Tout à fait.

Donc la solution proposée par Marc est valable.


Avec toujours la réserve que l'utilisateur doit savoir s'il faut hériter de
C1 ou C2, mais ce n'est peut-être pas un problème.

Rémy


1 2