Bonjour,
pour m'exercer j'essaie de créer une classe u64 (unsigned codés sur 64 bits), en surchargeant les opérations sur cette classe:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
struct u64
{
     u32 faible;
     u32 fort;
 
     u64(u64 &right) {
          faible = right.faible;
          fort = right.fort;
     }
 
     // u32 -> u64
     u64(u32 right) {
          faible = right;
          fort = 0;
     }
 
     u64& operator=(const u64 &right) {
          faible = right.faible;
          fort = right.fort;
          return (*this);
     }
 
     inline static void multiplie(const u32 left, const u32 right, u64 &result) {
          u32 a,b,c,d,i,j,k,l;
          a = left & 0xffff;
          b = ((u32)left) >> 16;
          c = right & 0xffff;
          d = ((u32)right) >> 16;
 
          i = a * c;
          j = a * d;
          k = b * c;
          l = b * d;
          j += k;
          if(j < k)
               l++;
 
          result.faible = i + (j << 16);	// pas d'overFlow possible
          result.fort = l + (((u32)j) >> 16);	// idem
     }
 
     // u64 -> u32
     operator unsigned int const (void) {
          return faible;
     }
 
};
 
u64 operator*(const u64 &left, const u64 &right) {
     u64 result;
     u64 i,j,k;
 
     u64::multiplie(left.faible,right.faible,result);
     if((left.fort) || (right.faible)) {
          u64::multiplie(left.fort,right.faible,j);
          u64::multiplie(left.faible,right.fort,k);
          result.fort += j.faible + k.faible;
     }
 
     return result;
}
mais si j'execute le code suivant:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
u64 a = 1 << 31;
u64 b = 1 << 31;
u64 c = a * b;
c vaut 0 !

alors que ceci:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
u64 a = 1 << 31;
u64 b = 1 << 31;
u64 c;
c = a * b;
me renvoie bien le bon résultat 1 << 62.

en step-by-step, on voit que dans le premier cas c'est l'opérateur de copie qui est utilisé, et pour une raison qui m'échappe, dans le second cas le compilo préfère caster le résultat de a * b en u32 puis lui appliquer le constructeur 32 bits u64(u32 right) plutôt que d'utiliser directement l'opérateur de copie 64 bits u64(u64 &right).
A noter que si j'enlève le code permettant le cast de u64 à u32, ou le constructeur 32 bits u64(u32 right), alors il utilise bien l'opérateur de copie 64 bits u64(u64 &right) et la valeur de c devient juste dans les 2 morceaux de codes ci-dessus.

D'où ma question: 1) commet expliquer au compilo que c'est bien l'opérateur de copie 64 bit qu'il doit utiliser dans ce cas, et pas le constructeur 32 bits ?

et 2) (question subsidiaire): est-ce que c'est possible de désactiver le cast implicite dans le code:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
operator unsigned int const (void) {
     return faible;
}
un peu dans le genre du mot clé explicit qu'on peut ajouter devant:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
explicit u64(u32 right) {
     faible = right;
     fort = 0;
}
puisque en principe on voudrait plutôt que l'utilisateur puisse faire librement des:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
u64 a;
u32 b = 10;
a = b;
plutôt que des:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
u64 a = 1 << 50;
u32 b;
b = a;
(qui eux devraient générer une erreur sauf si on cast b = (u32)a; )

merci d'avance !