
Link
:Godzil
: [...]
C'est marrant, dans mon cours sur les collections en java, on nous a justement dit d'utiliser
List myList = new ArrayList();
Justement pour être sûr que l'interface ne changerait pas, et qu'il suffit de modifier une ligne pour changer l'implémentation...
ConteneurSpecialise conteneur_spe = new ConteneurSpecialise() Conteneur conteneur = conteneur_spe;
spectras :
Note quand même : ((machin*)truc) => ce code est erroné. Il faut écrire static_cast<machin*>(truc)
Tu risques plein de bugs étranges sinon, parce que l'adresse de la classe de base machin dans l'objet truc n'est pas forcément l'adresse de l'objet truc lui-même.
Euh j'ai l'impression que tu pipotes complètement, pour le coup... si truc est un derivedmachin*, static_cast<machin*>(truc) et (machin*)truc sont rigoureusement équivalents ^^ (et heureusement, t'imagines le carnage qu'il y aurait avec les conversions automatiques quand tu as de l'héritage multiple ?)
La différence, c'est que static_cast<> ne change pas le statut "const ou pas", et qu'il est plus restreint puisqu'il ne fera pas de reinterpret_cast<> si le static_cast<> n'est pas applicable... Rien à voir avec les adresses physiques, qui peuvent être ajustées dans les deux cas![]()
(section concernant le reinterpret_cast):
A pointer to an object can be explicitly converted to a pointer to an object of different type. Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
(section concernant le static_cast): An rvalue of type “pointer to cv1 B,” where B is a class type, can be converted to an rvalue of type “pointer to cv2 D,” where D is a class derived (clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D. The null pointer value (4.10) is converted to the null pointer value of the destination type. If the rvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.
Oui j'ai bien compris, mais ma remarque portait précisément sur le cas où les fonctions ne sont *pas* virtuelles ^^ (« En fait moi ce qui me semble bizarre dans votre truc c'est le contraire : les méthodes non virtuelles. »)C'est vrai, et c'est pour ça que les méthodes non virtuelles sont rarement utilisées dès lors qu'il y a de l'héritage dans l'air.
ExtendeDNon, on n'aurait pas pu compiler. Bah oué mais justement c'est pas du Java
:spectras :Donc si ce n'était pas le cas on aurait pas pu compiler ? C'est marrant parce qu'en Java toute les surchages de toute la hiérarchie sont toujours accessibles.
Coup de bol (ou non, selon le point de vue), la classe complex définit un opérateur de conversion implicite depuis le type double.
spectras
:spectras :
Note quand même : ((machin*)truc) => ce code est erroné. Il faut écrire static_cast<machin*>(truc)
Tu risques plein de bugs étranges sinon, parce que l'adresse de la classe de base machin dans l'objet truc n'est pas forcément l'adresse de l'objet truc lui-même.
Euh j'ai l'impression que tu pipotes complètement, pour le coup... si truc est un derivedmachin*, static_cast<machin*>(truc) et (machin*)truc sont rigoureusement équivalents ^^ (et heureusement, t'imagines le carnage qu'il y aurait avec les conversions automatiques quand tu as de l'héritage multiple ?)
La différence, c'est que static_cast<> ne change pas le statut "const ou pas", et qu'il est plus restreint puisqu'il ne fera pas de reinterpret_cast<> si le static_cast<> n'est pas applicable... Rien à voir avec les adresses physiques, qui peuvent être ajustées dans les deux cas![]()
Nonon, la conversion classique est équivalente au reinterpret_cast, et elle ne fait pas d'ajustement des adresses physiques particulière pour les classes. C'est particulièrement dangereux dans le cas d'héritage multiple comme tu le soulignes, et c'est pour ça qu'il y a un static_cast.
(soit dit en passant, la conversion par reinterpret_cast, même en héritage simple, n'est pas garantie par le standard)
En particulier, l'expression que j'ai surligné en rouge n'est pas définie par la norme. Au temps pour l'équivalence avec le static_cast, donc.
C++98/C++03, section 5.4 "Explicit type conversion (cast notation)" :
1 The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is a reference
type, otherwise the result is an rvalue. [Note: if T is a non-class type that is cv-qualified, the cv-qualifiers
are ignored when determining the type of the resulting rvalue; see 3.10. ]
2 An explicit type conversion can be expressed using functional notation (5.2.3), a type conversion operator
(dynamic_cast, static_cast, reinterpret_cast, const_cast), or the cast notation.
cast-expression:
unary-expression
( type-id ) cast-expression
3 Types shall not be defined in casts.
4 Any type conversion not mentioned below and not explicitly defined by the user (12.3) is ill-formed.
5 The conversions performed by
— a const_cast (5.2.11),
— a static_cast (5.2.9),
— a static_cast followed by a const_cast,
— a reinterpret_cast (5.2.10), or
— a reinterpret_cast followed by a const_cast,
can be performed using the cast notation of explicit type conversion. The same semantic restrictions and
behaviors apply. If a conversion can be interpreted in more than one of the ways listed above, the interpretation
that appears first in the list is used, even if a cast resulting from that interpretation is ill-formed.
spectras :
Ah, j'ai passé sur cette définition. Je pensais que ça faisait toujours un reinterpret_cast suivi éventuellement par un const_cast.....parce que c'est ce que fait le compilateur de VC6, et que j'avais rencontré le problème![]()
class Base1 { public: const int x; Base1(int x): x(x) {} }; class Base2 { public: const int x; Base2(int x): x(x) {} }; class Derived : public Base1, public Base2 { public: Derived(int a,int b): Base1(a), Base2(b) {} }; int main() { Derived *d = new Derived(7,42); Base1 *a = d; Base2 *b = d; return a->x==7 && b->x==42 ? 0 : 123; }