60

pencil
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

61

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...

Tu as pas cité un peu trop de trucs ?

Sinon je vois pas le rapport, déjà, on parle du C++ et pas du java

Ensuite, ce que tu fais c'est pas forcement la meme chose que ce dont on parle actuellement
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

62

Si si on parle quand même de la même chose... L'exemple donné est valable quel que soit le langage objet utilisé...
Conteneur conteneur = new ConteneurSpécialisé();
C'est super pratique, tu peux changer de spécialisation en ne modifiant qu'une ligne de ton code, en fonction de l'utilisation que tu fais du conteneur (pour améliorer les perfs).
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

63

Ca laisse quand meme montrer un problème de conception, je suis désolé. et je ne parle QUE du C++ ou les interfaces (ou quelque soit le nom du C#, java ou Objective C etc...) ne sont pas clairement définies.

Ton code la laisse entre l'utilisation des Interfaces (ce qu'on appel Protocol en Objective C par ex)

Mais meme dans ce cas, ça laisse transparaitre un problème de conception. Si "ConteneurSpecialise" est une classe fille de Conteneur, fait un "ConteneurSpecialise conteneur = new ConteneurSpecialise()" ne pose aucun soucis a tout le reste du code, meme si tu fait appel a des fonctions qui ne prennent qu'un "Conteneur" et pas un "ConteneurSpecialise"

c'est d'autant plus propre et evite les emmerdes soulevé plus haut, et ce pas que sur le plan compilo, mais sur le plan conceptuel.

Libre a toi derriere de faire un

ConteneurSpecialise conteneur_spe = new ConteneurSpecialise()
Conteneur conteneur = conteneur_spe;
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

64

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 ? couic)
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 smile

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.
Je cite :
(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.

Ah, autre précision : le reinterpret_cast n'a pas le droit de retirer la constness de l'expression. Mais il peut la mettre, en revanche.




A titre de comparaison, voici ce qui est dit pour le static_cast dans ce cas :
(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.

65

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.
Cela dit, ça reste utile pour les méthodes privées de la classe par exemple, ou pour les méthodes qui ne sont pas destinées à être redéfinies, ou encore pour les méthodes inline.
ExtendeD
:
spectras :
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.
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.
Non, on n'aurait pas pu compiler. Bah oué mais justement c'est pas du Java wink
Cela dit une autre option aurait pu être d'autoriser explicitement l'utilisation des surcharges de la classe de base en faisant un
using Base::f;
(le using peut être récursif, si la classe Base hérite elle-même d'une autre classe et a déclaré un using SaBase::f; )

66

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 ? couic)
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 smile

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.

Mais qu'est-ce que tu racontes ? confus
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.


Donc c'est bien d'un static_cast qu'il s'agit, pas d'un reinterpret_cast ^^

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

67

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 grin
Du coup j'ai pas pris la peine de vérifier ^^.

68

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 grin

couic
Enfin ça commence à être un chouilla vieux, VC6 tongue

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

69

Cela dit faudrait faire un test case et le soumettre aux compilos pour voir.

70

Te gène pas si tu as le temps tongue
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

71

Enfin le test case il est simple :
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;
}

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)