BTW : Je cherche à répondre aux parties de cette question telles qu'elles ont été posées. Je ne cherche pas non plus à reproduire toutes les informations contenues dans d'autres réponses valables. La prime cherche quelque chose de différent de la question posée, donc je n'y répondrai pas.
Il est en fait assez simple de fournir une multiplication matricielle. Puisque je ne propose pas de décrire les structures de données pour représenter une matrice et d'implémenter complètement les opérations et les contrôles de validité sur celles-ci, je vais juste fournir des squelettes pour illustrer.
*Exemple 1 : `operator()` en tant que fonction membre**
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const;
};
M M::operator*(const M &rhs) const
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = a*b; // this relies on M having appropriate constructor(s) to copy or move the result of a*b into c
M d;
d = a * b; // this relies on M having appropriate operator=() to assign d to the result of a*b
}
Ce qui précède met en œuvre operator*()
comme fonction membre. Donc, fonctionnellement, c = a*b
est équivalent à c = a.operator*(b)
. Le site const
Les qualificatifs représentent le fait qu'une multiplication de matrice a*b
ne change généralement pas a
o b
.
*Exemple 2 : `operator()` en tant que fonction non membre**
Maintenant, operator*()
peut également être mis en œuvre en tant que non-membre (éventuellement une friend
), avec un squelette qui ressemble à
class M // our basic matrix class, different operator *
{
public:
// assume other constructors and members to set things up
friend M operator*(const M &lhs, const M &rhs);
};
M operator*(const M &lhs, const M &rhs)
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
// same main() as before
Notez que, dans ce cas, a*b
est maintenant équivalent à operator*(a, b)
.
Si vous souhaitez utiliser les deux formes, il faut veiller à éviter toute ambiguïté. Si les deux formes de operator*()
à condition qu'elles soient toutes deux des correspondances valides dans une déclaration telle que c = a*b
et le compilateur n'a aucun moyen de choisir une forme plutôt qu'une autre. Le résultat est un code qui ne compile pas.
*Exemple 3 : surcharge `operator()`**
Il est également possible de surcharger operator*()
- par exemple, pour multiplier une matrice par un scalaire.
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const; // as in first example
M operator*(double scalar) const; // member form
friend M operator*(double scalar, const M &rhs); // non-member form
};
M M::operator*(double scalar) const
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
M operator*(double scalar, const M &m)
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = b * 2.0; // uses the member form of operator*() above
M d;
d = 2.0*a; // uses the non-member form of operator*() above
}
Dans l'article ci-dessus b*2.0
équivaut à un appel de b.operator*(2.0)
y 2.0*a
à un appel du non-membre operator*(2.0, a)
. Les formes membres ne peuvent généralement être utilisées que dans des expressions où l'opérande de gauche est de type M
. Donc 2.0*a
ne fonctionnera pas si seules les formes membres de operator*()
est fourni.
Discussion
En dehors des problèmes d'ambiguïté évoqués ci-dessus, il y a d'autres éléments à prendre en compte lors de la surcharge d'opérateurs.
- Il n'est pas possible de modifier la précédence ou l'associativité des opérateurs à partir de leur spécification dans les règles du langage. Ainsi, dans l'expression
a+b*c
le *
aura toujours une plus grande priorité que l'option +
. C'est aussi la raison pour laquelle ce n'est pas une bonne idée de surcharger ^
pour l'exponentiation en C++, car ^
a une priorité inférieure à celle de +
en C++ (étant une opération de type bit à bit sur des types entiers). Ainsi, a + b^c
est en fait équivalent en C++ à (a + b)^c
et non à a + (b^c)
(ce que toute personne ayant des connaissances de base en algèbre attendrait).
- Le langage spécifie un ensemble d'opérateurs, et il n'est pas possible d'en créer de nouveaux. Par exemple, il n'existe pas de
**
en C++, tel que a ** b
soulève a
au pouvoir de b
(ce que d'autres langues peuvent faire), et il n'est pas possible d'en créer une.
- Tous les opérateurs ne peuvent pas être surchargés.
Un des opérateurs qui ne peut pas être surchargé en C++ est .*
. Il n'est donc pas possible d'utiliser un tel opérateur comme vous le feriez dans Matlab. Je suggère généralement de NE PAS essayer d'obtenir le même effet en utilisant d'autres opérateurs, parce que les contraintes ci-dessus affecteront cela (et provoqueront un comportement contre-intuitif des expressions). Au lieu de cela, fournissez simplement une autre fonction nommée pour faire le travail. Par exemple, en tant que fonction membre
class M
{
public:
// other stuff
M ElementWiseProduct(const M &) const;
};