web-dev-qa-db-fra.com

Que signifie "operator = doit être un membre non statique"?

Je suis en train de créer une liste à double liaison, et j'ai surchargé l'opérateur = pour que la liste soit égale à une autre:

template<class T>
void operator=(const list<T>& lst)
{
    clear();
    copy(lst);
    return;
}

mais j'obtiens cette erreur lorsque j'essaye de compiler:

container_def.h(74) : error C2801: 'operator =' must be a non-static member

De plus, si cela aide, la ligne 74 est la dernière ligne de la définition, avec le "}".

25
user98188

Exactement ce qu'il dit: les surcharges d'opérateur doivent être des fonctions membres. (déclaré à l'intérieur de la classe)

template<class T>
void list<T>::operator=(const list<T>& rhs)
{
    ...
}

De plus, c'est probablement une bonne idée de renvoyer le LHS de = pour pouvoir le chaîner (comme a = b = c) - alors faites-le list<T>& list<T>::operator=....

23
v3.

Mettez cet opérateur dans votre définition de classe. Il doit être membre car operator= est spécial et vous ne gagneriez rien de toute façon en l'écrivant en tant que non-membre. Un opérateur non membre présente deux avantages principaux importants:

  • Conversions implicites de droite et le côté gauche de l'invocation de l'opérateur
  • Pas besoin de connaître les internes de la classe. La fonction peut être réalisée en tant que non-membre non-ami.

Pour operator=, les deux ne sont pas utilisables. L'affectation à un résultat temporaire d'une conversion n'a pas de sens et operator= aura besoin d'accéder aux internes dans la plupart des cas. En outre, un operator= est automatiquement fourni par C++ si vous n'en fournissez pas (ce que l'on appelle l'opérateur d'affectation de copie). Permettant de surcharger operator= en tant que non-membre aurait introduit une complexité supplémentaire pour apparemment aucun gain pratique, et donc ce n'est pas autorisé.

Modifiez donc votre code pour qu'il ressemble à ceci (cela suppose que le operator= est pas un opérateur d'affectation de copie, mais l'affectation à partir d'un list<T> à autre chose. Cela ne ressort pas clairement de votre question):

class MyClass {
...
    template<class T>
    MyClass& operator=(const list<T>& lst)
    {
        clear();
        copy(lst);
        return *this;
    }
...
};

C'est assez standard qu'un operator= renvoie une référence à lui-même. Je vous recommande d'adhérer à cette pratique. Il semblera familier aux programmeurs et pourrait provoquer des surprises s'il renvoyait void tout d'un coup.

19

Si vous surchargez un opérateur en tant que fonction membre, vous devez utiliser ce modèle:

class A {
  A& operator=(const A& other) {
    if (this != &other) {
      ...
    }
    return *this;
  }
}

Trois choses à noter:

  1. Vérifiez l'auto-affectation avec l'opérateur d'affectation (comme ci-dessus);
  2. L'argument doit être une référence const; et
  3. Renvoie le résultat de l'opération sous forme de référence non const où vous retournez * this pour permettre le chaînage des opérateurs.

Vous pouvez également surcharger un opérateur externe à la classe. Cela n'est pas pertinent pour cet exemple car vous ne pouvez pas le faire avec l'opérateur d'affectation mais cela vaut la peine d'être noté car dans de nombreux cas, il est supérieur aux fonctions membres. La forme typique est:

class A {
  friend const A& operator+(const A& a, const A& b);
  ...
}
const A& operator+(const A& a, const A& b) {
  A& ret = ...
  return ret;
}

Celui-ci renvoie une référence const donc vous ne pouvez pas faire ceci:

(a + b) = c
6
cletus