Se você definir operator<<
como uma função de membro, ela terá uma sintaxe decomposta diferente do que se você usasse um não membro operator<<
. Um não membro operator<<
é um operador binário, onde um membro operator<<
é um operador unário.
// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);
struct MyObj
{
// This is a member unary-operator, hence one argument
MyObj& operator<<(std::ostream& os) { os << *this; return *this; }
int value = 8;
};
// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
return os << myObj.value;
}
Então .... como você realmente os chama? Os operadores são estranhos em alguns aspectos, vou desafiá-lo a escrever a operator<<(...)
sintaxe em sua cabeça para fazer as coisas fazerem sentido.
MyObj mo;
// Calling the unary operator
mo << std::cout;
// which decomposes to...
mo.operator<<(std::cout);
Ou você pode tentar chamar o operador binário não membro:
MyObj mo;
// Calling the binary operator
std::cout << mo;
// which decomposes to...
operator<<(std::cout, mo);
Você não tem obrigação de fazer esses operadores se comportarem intuitivamente ao transformá-los em funções de membro, você pode definir operator<<(int)
para o deslocamento à esquerda alguma variável de membro se quiser, entenda que as pessoas podem ser um pouco pegas de surpresa, não importa quantos comentários você possa escrever.
Quase por último, pode haver momentos em que ambas as decomposições para uma chamada de operador sejam válidas, você pode ter problemas aqui e nós adiaremos essa conversa.
Por último, observe como pode ser estranho escrever um operador de membro unário que supostamente se pareça com um operador binário (já que você pode tornar os operadores de membro virtuais ..... também tentando não devolver e percorrer este caminho .... )
struct MyObj
{
// Note that we now return the ostream
std::ostream& operator<<(std::ostream& os) { os << *this; return os; }
int value = 8;
};
Esta sintaxe irritará muitos programadores agora ....
MyObj mo;
mo << std::cout << "Words words words";
// this decomposes to...
mo.operator<<(std::cout) << "Words words words";
// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");
Observe como o cout
é o segundo argumento na cadeia aqui .... estranho, certo?