Operatori di sovraccarico come funzione membro o non membro (amico)?

Attualmente sto creando una class di utilità che avrà sovraccaricato gli operatori al suo interno. Quali sono i pro e i contro di renderli membri o non membri ( friend ) delle funzioni? O è importante? Forse c’è una buona pratica per questo?

Ogni operatore ha le sue considerazioni. Ad esempio, l’operatore << (quando viene utilizzato per l'output del flusso, non lo spostamento dei bit) ottiene un ostream come primo parametro, quindi non può essere un membro della classe. Se stai implementando l'operatore di addizione, probabilmente vorrai beneficiare di conversioni di tipo automatiche su entrambi i lati, quindi andrai anche con un non-membro, ecc ...

Per quanto riguarda il permettere la specializzazione attraverso l’ereditarietà, un modello comune consiste nell’implementare un operatore non membro in termini di una funzione membro virtuale (ad esempio, l’operatore << chiama una funzione virtuale print () sull'oggetto che viene passato).

Vorrei andare con “C ++ Coding Standards: 101 Rules, Guidelines and Best Practices”: se puoi farlo come non-member, fallo come non-member function (nello stesso namespace).

Uno dei motivi: funziona meglio con la conversione di tipo implicita. Un esempio: hai una class complessa con un operatore sovraccarico *. Se si desidera scrivere 2.0 * aComplexNumber, è necessario che l’operatore * sia una funzione non membro.

Un’altra ragione: meno accoppiamento. Le funzioni non associate sono meno abbinate alle funzioni membro. Questa è quasi sempre una buona cosa.

Se pianifichi di implementare gli operatori di streaming (<< e >>), allora saranno metodi non membri perché il tuo object si trova sulla sinistra dell’operatore.

Se pensate di implementare ->, () o [] sono naturalmente metodi membri.

Per gli altri (confronto e matematica) dovresti dare un’occhiata a Boost.Operators , è davvero d’aiuto.

Ad esempio, se si desidera implementare i seguenti operatori:

 MyClass& MyClass::operator+=(int); MyClass operator+(const MyClass&, int); MyClass operator+(int, const MyClass&); 

Devi solo scrivere:

 class MyClass: boost::operator::addable // no need for public there { public: MyClass& operator+=(int); private: }; 

I 2 operator+ verranno generati automaticamente come non membri che ti consentiranno di beneficiare delle conversioni automatiche. E verranno implementati in modo efficiente in termini di operator+= modo da scrivere il codice una sola volta.

Se stai implementando op, allora probabilmente dovrai implementare op =. cioè se si sta sovraccaricando + operatore, allora si dovrebbe implementare + =. Assicurati di restituire const a un object se stai facendo un operatore post-incremento o sovraccarico +. Quindi, se sovraccarichi l’operatore +, quindi implementalo come operatore non membro e usa + = operatore al suo interno. Per es.

 const A operator+(const A& lhs, const A& rhs) { A ret(lhs); ret += rhs; return ret; } 

Per gli operatori binari, una limitazione delle funzioni membro è che l’object di sinistra deve essere del tipo di class. Questo può limitare l’utilizzo simmetrico dell’operatore.

Considera una semplice class di stringa:

 class str { public: str(const char *); str(const str &other); }; 

Se si implementa l’operatore + come funzione membro, mentre str("1") + "2" verrà compilato, "1" + str("2") non verrà compilato.

Ma se si implementa l’operatore + come una funzione non membro, entrambe le affermazioni saranno legali.

Non c’è niente come le migliori pratiche, ma dipende dall’operatore che stai sovraccaricando ..

Per es.

  1. >> e << non possono essere sovraccaricati come funzioni membro.

  2. Supponiamo di voler fare così: obj1 = 2 * obj2 quindi vai per la funzione non membro .

Per la funzione membro di overloading dell’operatore binario richiede solo 1 parametro (l’object invocante viene passato in modo imprevisto) mentre la funzione non membro prende 2 parametri.