Sobrecarregar os operadores como function de membro ou function de não membro (amigo)?

Atualmente, estou criando uma class de utilitário que sobrecarregará os operadores. Quais são os prós e contras de fazer com que sejam membros ou não-membros ( friend )? Ou isso importa em tudo? Talvez haja uma prática recomendada para isso?

Cada operador tem suas próprias considerações. Por exemplo, o operador << (quando usado para saída de fluxo, não para transferência de bit) recebe um ostream como seu primeiro parâmetro, portanto, ele não pode ser um membro de sua classe. Se você estiver implementando o operador de adição, provavelmente desejará se beneficiar de conversões de tipo automáticas em ambos os lados, portanto, você também poderá optar por um não membro, etc.

Quanto a permitir a especialização por inheritance, um padrão comum é implementar um operador não membro em termos de uma function de membro virtual (por exemplo, operador << chama uma função virtual print () no objeto que está sendo passado).

Eu iria com “C ++ Coding Standards: 101 regras, orientações e melhores práticas”: se você pode fazê-lo como function não membro, faça isso como function não-membro (no mesmo espaço de nomes).

Uma das razões: funciona melhor com conversão de tipo implícita. Um exemplo: você tem uma class complexa com um operador sobrecarregado *. Se você quiser gravar 2.0 * aComplexNumber, precisará do operador * para ser uma function não-membro.

Outro motivo: menos acoplamento. Funções não membro, menos acopladas que as funções membro. Isso é quase sempre uma coisa boa.

Se você planeja implementar operadores de streaming (<< e >>), eles serão methods que não são membros, pois seu object está à esquerda do operador.

Se você planeja implementar ->, () ou [] eles são naturalmente membros.

Para os outros (comparação e matemática) você deve verificar Boost.Operators , isso realmente ajuda.

Por exemplo, se você deseja implementar os seguintes operadores:

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

Você só precisa escrever:

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

O operator+ 2 operator+ será gerado automaticamente como não membros, o que permitirá que você se beneficie de conversões automáticas. E eles serão implementados com eficiência em termos de operator+= portanto, você escreve o código apenas uma vez.

Se você está implementando op, então provavelmente você precisa implementar op =. ou seja, se você está sobrecarregando + operador, então você deve implementar + =. Certifique-se de que você está retornando const para um object se você estiver fazendo pós-incremento ou sobrecarga + operador. Portanto, se você sobrecarregar o operador +, implemente-o como um operador não-membro e use o operador + = dentro dele. Por exemplo

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

Para operadores binários, uma limitação das funções de membro é que o object da esquerda deve ser do tipo da sua class. Isso pode limitar o uso do operador simetricamente.

Considere uma class de string simples:

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

Se você implementar operator + como uma function de membro, enquanto str("1") + "2" for compilado, "1" + str("2") não será compilado.

Mas se você implementar o operador + como uma function não-membro, ambas as instruções serão legais.

Não há nada como as práticas recomendadas, mas depende do operador que você está sobrecarregando.

Por exemplo

  1. >> e << não podem ser sobrecarregados como funções de membro.

  2. Suponha que você queira fazer assim: obj1 = 2 * obj2, então vá para a function não-membro .

Para a function de membro de sobrecarga do operador binário, é necessário apenas 1 parâmetro (o object invocador é impiedosamente transmitido), enquanto a function de não membro leva 2 parâmetros.

Intereting Posts