Pourquoi une fonction non-membre ne peut-elle pas être utilisée pour surcharger l'opérateur d'affectation?

l'opérateur d'affectation peut être surchargé en utilisant une fonction membre mais pas une fonction non-membre friend :

class Test
{
    int a;
public:
    Test(int x)
        :a(x)
    {}
    friend Test& operator=(Test &obj1, Test &obj2);
};

Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test.
{
    return obj1;
}

Il la cause de cette erreur:

erreur C2801: 'operator =' doit être un non-membre statique

pourquoi une fonction friend ne peut-elle pas être utilisée pour surcharger l'opérateur d'affectation? Le compilateur permet de surcharger d'autres opérateurs tels que += et -= par friend . Quel est le problème ou la limite inhérente à l'appui de operator= ?

26
demandé sur Jamal 2010-10-14 17:29:51

9 réponses

parce que la valeur par défaut operator= fournie par le compilateur (la copie par membre) aurait toujours la priorité. I. e. votre ami operator= ne sera jamais appelé.

EDIT: cette réponse répond au

Quel est le problème/la limitation inhérent au Support = opérateur ?

partie de la question. Les autres réponses ici citent la partie de la norme qui dit que vous ne pouvez pas faire il, mais ce est très probablement pourquoi cette partie de la norme a été écrite de cette façon.

26
répondu Billy ONeal 2010-10-14 13:43:58

tout d'abord, il convient de noter que cela n'a rien à voir avec l'exploitant mis en œuvre en tant que ami spécifiquement. Il s'agit en fait de mettre en œuvre la copie-assignation en tant que fonction membre ou en tant que Fonction non-membre (autonome). Que cette fonction autonome soit un ami ou non n'est pas du tout pertinent: elle pourrait l'être, elle pourrait ne pas l'être, selon ce qu'elle veut accéder à l'intérieur de la classe.

Maintenant, la réponse à cette la question est donnée dans le D&E livre ( La Conception et l'Évolution de C++ ). La raison en est que le compilateur déclare/définit toujours un opérateur membre copy-assignment pour la classe (si vous ne déclarez pas votre propre opérateur membre copy-assignment).

si la langue permettait aussi de déclarer l'opérateur copy-assignment comme une fonction autonome( non-membre), vous pourriez vous retrouver avec la suivante

// Class definition
class SomeClass {
  // No copy-assignment operator declared here
  // so the compiler declares its own implicitly
  ...
};

SomeClass a, b;

void foo() {
  a = b;
  // The code here will use the compiler-declared copy-assignment for `SomeClass`
  // because it doesn't know anything about any other copy-assignment operators
}

// Your standalone assignment operator
SomeClass& operator =(SomeClass& lhs, const SomeClass& rhs);

void bar() {
  a = b;
  // The code here will use your standalone copy-assigment for `SomeClass`
  // and not the compiler-declared one 
}

comme vu ci-dessus par exemple, la sémantique de la copie-assignation changerait au milieu de l'Unité de traduction - avant la déclaration de votre opérateur autonome la version du compilateur est utilisée. Après la Déclaration, votre version est utilisée. Le comportement du programme changera en fonction de l'endroit où vous placez la déclaration de votre opérateur autonome copy-assignment.

cela a été considéré comme un danger inacceptable (et c'est le cas), donc C++ ne permet pas à l'opérateur copy-assignment d'être déclaré comme une fonction autonome.

il est vrai que dans votre exemple particulier, qui utilise une fonction ami spécifiquement, l'opérateur est déclaré très tôt, à l'intérieur de la définition de la classe (puisque c'est ainsi que les amis sont déclarés). Donc, dans votre cas, le compilateur va, bien sûr, connaître l'existence de votre opérateur. Cependant, du point de vue du langage C++ le grand problème n'est pas lié à un ami fonctions. Du point de vue du langage C++, il s'agit des fonctions de membre par rapport aux fonctions de non-membre, et la surcharge de copie par un non-membre est tout simplement interdite pour les raisons décrites ci-dessus.

32
répondu AnT 2015-07-16 19:03:26

$13.5.3 - "Un opérateur d'affectation doit être mis en œuvre par un non-fonction membre statique avec un seul paramètre. parce qu'un opérateur d'affectation de copie= est implicitement déclaré pour une classe si elle n'est pas déclarée par l'utilisateur (12.8), un opérateur d'affectation de classe de base est toujours caché par l'opérateur d'affectation de copie de la classe dérivée."

8
répondu Chubsdad 2010-10-14 13:40:00

parce qu'il y a des opérateurs qui doivent être membres. Ces opérateurs sont:

operator[]

operator=

operator()

operator->

et les opérateurs de conversion de type, comme operator int .

bien que l'on puisse expliquer pourquoi exactement operator = doit être un membre, leur argument ne peut pas s'appliquer à d'autres dans la liste, qui me fait croire que la réponse à "Pourquoi" est "Juste parce que".

HTH

6
répondu Armen Tsirunyan 2011-12-11 16:13:59

operator= est une fonction de membre spéciale que le compilateur fournira si vous ne la déclarez pas vous-même. En raison de ce statut spécial de operator= il est logique ro exiger d'être une fonction de membre, il n'y a donc aucune possibilité d'être à la fois un membre généré par compilateur operator= et un ami utilisateur déclaré operator= et aucune possibilité de choisir entre les deux.

3
répondu Bart van Ingen Schenau 2010-10-14 13:42:06

pourquoi la fonction ami ne peut-elle pas être utilisée pour surcharger l'opérateur d'affectation?

courte réponse: juste parce que .

réponse un peu plus longue: C'est ainsi que la syntaxe a été corrigée. Quelques opérateurs doivent être membres fonctions 151980920". L'opérateur d'affectation est l'un des,

1
répondu sbi 2010-10-14 13:40:57

L'intention de operator= est une opération d'affectation de l'objet courant. Alors le LHS, ou lvalue, est un objet du même type.

considère un cas où le LHS est un entier ou un autre type. C'est un cas traité par la fonction operator int() ou une fonction correspondante operator T() . Par conséquent, le type de LHS est déjà défini, mais une fonction non-membre operator= pourrait enfreindre cette règle.

donc il est évité.

0
répondu Harihara Sudhan Sundararajan 2012-10-10 21:07:17

parce qu'il y a déjà une fonction de surcharge implicite de l'opérateur pour' = ' dans la classe à faire copie superficielle . Donc, même si vous surchargez en utilisant une fonction , vous ne pourrez jamais l'appeler car tout appel fait par nous appellerait la méthode implicite de copie superficielle plutôt que la fonction "ami surchargé".

0
répondu Nitin Gautam 2015-05-28 04:35:58

Ce post s'applique à C++11

pourquoi quelqu'un voudrait un non-membre operator= ? Bien, avec un membre operator= alors le code suivant est possible:

Test const &ref = ( Test() = something ); 

qui crée une référence pendante. Un exploitant non-membre fixerait ceci:

Test& operator=(Test &obj1, Test obj2)

parce que maintenant la prvalue Test() ne se liera pas à obj1 . En fait, cette signature permettrait d'imposer que nous ne renvoyez jamais une référence pendante (à moins que nous n'en ayons reçu une, bien sûr) - la fonction renvoie toujours une valeur l "valide" parce qu'elle renforce le fait d'être appelé avec une valeur l.

cependant dans C++11 Il y a maintenant un moyen de spécifier qu'une fonction membre ne peut être appelée que sur lvalues, de sorte que vous pouvez atteindre le même objectif en écrivant la fonction membre:

Test &operator=(Test obj2) &
//                        ^^^

maintenant le code ci-dessus avec référence pendante ne pourra pas être compilé.


NB. operator= devrait prendre le côté droit par la valeur ou la référence de const. La prise de valeur est utile lors de la mise en œuvre de l'idiome copie et échange , une technique permettant d'écrire facilement des opérateurs sûrs (mais pas nécessairement les plus rapides) de copie-assignation et de déplacement-assignation.

0
répondu M.M 2017-05-23 12:10:29