Sylvain
2006-06-25 03:56:19 UTC
static std::string const ma_chaine ("://");
const implique static si il n'y a pas une déclarationantérieure qui indique que c'est avec un "linkage" externe.
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 ?
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.