web-dev-qa-db-fra.com

Surcharge de l'opérateur en dehors de la classe

Il existe deux façons de surcharger les opérateurs pour une classe C++:

À l'intérieur de la classe

class Vector2
{
public:
    float x, y ;

    Vector2 operator+( const Vector2 & other )
    {
        Vector2 ans ;
        ans.x = x + other.x ;
        ans.y = y + other.y ;
        return ans ;
    }
} ;

Hors classe

class Vector2
{
public:
    float x, y ;
} ;

Vector2 operator+( const Vector2& v1, const Vector2& v2 )
{
    Vector2 ans ;
    ans.x = v1.x + v2.x ;
    ans.y = v1.y + v2.y ;
    return ans ;
}

(Apparemment, en C #, vous ne pouvez utiliser que la méthode "Outside Class".)

En C++, quelle voie est la plus correcte? Quel est préférable?

43
bobobobo

La question de base est "Voulez-vous que les conversions soient effectuées sur le paramètre de gauche d'un opérateur?". Si oui, utilisez une fonction gratuite. Si non, utilisez un membre de la classe.

Par exemple, pour operator+() pour les chaînes, nous voulons que les conversions soient effectuées afin de pouvoir dire des choses comme:

string a = "bar";
string b = "foo" + a;

où une conversion est effectuée pour transformer le char * "foo" en un std::string. Donc, nous transformons operator+() pour les chaînes en une fonction libre.

52
anon

Premièrement: les deux façons différentes sont vraiment "la surcharge en tant que membre" et "la surcharge en tant que non-membre", et cette dernière a deux façons différentes de l'écrire (définition de classe as-friend-inside et définition de classe outside). Les appeler "classe interne" et "classe externe" va vous embrouiller.


Les surcharges pour + =, +, - =, -, etc. ont un schéma spécial:

struct Vector2 {
  float x, y;
  Vector2& operator+=(Vector2 const& other) {
    x += other.x;
    y += other.y;
    return *this;
  }
  Vector2& operator-=(Vector2 const& other) {
    x -= other.x;
    y -= other.y;
    return *this;
  }
};
Vector2 operator+(Vector2 a, Vector2 const& b) {
  // note 'a' is passed by value and thus copied
  a += b;
  return a;
}
Vector2 operator-(Vector2 a, Vector2 const& b) { return a -= b; } // compact

Ce modèle permet les conversions mentionnées dans les autres réponses pour l'argument LHS tout en simplifiant considérablement l'implémentation. (Le membre ou le non-membre autorise les conversions pour le RHS lorsqu'il est transmis en tant que const& ou par valeur, comme il se doit.) Bien sûr, cela ne s'applique que lorsque vous souhaitez réellement surcharger à la fois + = et +, - = et -, etc., mais cela reste courant.


De plus, vous voulez parfois déclarer votre non-membre op +, etc. comme friends dans la définition de classe en utilisant astuce Barton-Nackman , car en raison des caprices des modèles et de la surcharge , il peut ne pas être trouvé sinon .

16
Roger Pate

Il existe une excellente discussion de ce problème dans Meyer Effective C++: l'élément 24 est "Déclarer les fonctions non membres lorsque les conversions de type doivent s'appliquer à tous les paramètres" et l'élément 46 est "Définir les fonctions non membres dans les modèles lorsque les conversions de type sont souhaitées".

4
Francesco