Discussion:
Declaration de chaines constantes
(trop ancien pour répondre)
Sylvain
2006-06-25 03:56:19 UTC
Permalink
static std::string const ma_chaine ("://");
const implique static si il n'y a pas une déclaration
antérieure qui indique que c'est avec un "linkage" externe.
Même si le "static" est de toutes façons implicite, ne devrait-on pas
le mettre explicitement ?
De même, dans le code
struct A { virtual void f(); }
struct B { (virtual) void f(); }
le "virtual" est implicite ; doit-on tout de même l'écrire
explicitement ?
oups, peut être était-ce vraiment l'écriture intentionelle, se
traduisant par "si je n'indique pas 'virtual' ai-je tout de même les
attributs d'une déclaration (explicitement) virtuelle" ?

je ne vais pas me contenter d'un 'non' car cela a évidemment un impact
sur le design des classes et qu'il est utile d'avoir en tête ces
conséquences; si ce n'est pas ta question, cela servira peut être à
d'autres...

petit détour: en Java, une méthode d'instance est implicitement
virtuelle. ceci implique que:
- une résolution virtuelle est tjrs effectuée lors de l'appel d'une
méthode d'instance,
- un client ne peut bypasser la hiérarchie fournie par l'instance (quand
il invoque la méthode f() de l'instance c'est la méthode surchargée qui
est appelée.

à contrario en C++, la virtualité n'est pas implicite et doit être
déclarée par la classe qui introduit une méthode et souhaite la rendre
virtuelle, notons pour ne pas y revenir qu'il n'est pas possible de
rendre virtuele une méthode surchargée d'une classe parent qui n'était
pas originellmeent virtuelle.

cette non virtualité systématique implique que par défaut la surcharge
ne masque pas une méthode - le client d'une instance ayant surchargé des
méthodes de ses parents a accès aux méthodes de la classe comme à celles
du (ou des) parents (on omets ici les restriction de visibilité
explicite par protected et private, l'instance est considérée comme une
structure publique pour simplifier)

ainsi si:

struct A { void f(){} };
struct B : A { void f(){} };

alors ayant:

A a; B b;

a.f(); // est valide, bien sur et également
b.f(); // qui invoque B::f() avec le contexte de b, comme
(A& b).f(); // qui appelle A::f() avec le contexte de b

de plus la résolution n'étant pas "dynamisé" par une déclaration
virtuelle; un pointeur A* même initialisé avec une instance de B ne
verra que les méthodes de A:

A* pa = &B;
pa->f(); // invoque A::f() et non B::f().

(on vent arrêter là les détails verbieux)


si par contre nous déclarons la méthode virtuelle:

struct A { virtual void f(){} };
struct B : A { void f(){} };

alors la surcharge est maintenant masquante pour les clients de la classe:

b.f(); // invoque B::f()
(A& b).f(); // invoque également B::f()

bien B a accès aux détails de A, on peut avoir:

void B::f(){ A::f(); } // appel à la 'super-méthode'

autre impact, la résolution d'appel est dynamique donc:

A* pa = &B;
pa->f(); // invoque encore B::f().

la 1ière remarque (masquage) peut être vue comme une conséquence de ce
second point, ou on peut voir ce second point comme le moyen d'apporter
le premier (qui serait alors le but .. de l'encapsulation), le résultat
est le même (la motivation et ses arcanes sont très différentes).

voila.

Sylvain.
Fabien LE LEZ
2006-06-27 23:03:19 UTC
Permalink
D'abord, en C++, les méthodes d'une classe ne peuvent être raffinées par une
classe fille. Pour que l'implémentation d'une méthode puisse être redéfinie
dans les classes filles, cette dernière doit alors être marquée
comme 'virtual'
Ce n'est pas tout à fait ça. Déclarer une fonction "virtual" ne sert
que si on veut accéder aux fonctions de la classe dérivée, via un
pointeur (ou une référence) sur la classe de base.

Si les types statique et dynamique sont les mêmes, l'emploi de
"virtual" (et de la table qui va avec) est inutile.

Loading...