47 votes

Puis-je créer un nouvel opérateur en C++ et comment ?

Les tableaux de MATLAB prennent en charge les opérations matricielles et les opérations sur les éléments. Par exemple, M*N y M.*N . Il s'agit d'une manière assez intuitive de distinguer les deux opérations différentes. Si je veux mettre en œuvre des opérations similaires en C++, comment puis-je le faire ?

Puis-je créer un nouvel opérateur ? .* aussi ? Si oui, quelqu'un peut-il me donner des conseils ?

5voto

Peter Points 4026

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;
   };

1voto

Ernest Friedman-Hill Points 56605

C'est aussi simple (et aussi difficile !) que de définir une fonction nommée (dans ce cas) operator*() :

Matrix operator*(const Matrix &m1, const Matrix &m2) ...

donde Matrix est une classe que vous avez définie pour représenter les matrices.

1voto

suhdonghwi Points 426

Comme le disent d'autres réponses, la surcharge operator.* n'est pas possible.

Mais j'ai une bonne solution pour ta question, regarde. aquí .

Vous pouvez fournir n'importe quelle méthode dans l'opérateur- ish forme comme :

M <matrix_mul> N

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X