Como sobrecarregar corretamente o operador << para um ostream?
-
20-08-2019 - |
Pergunta
Eu estou escrevendo uma biblioteca matriz pequeno em C ++ para operações de matriz. No entanto o meu compilador reclama, onde antes isso não aconteceu. Este código foi deixado em uma prateleira por 6 meses e entre eu atualizei meu computador a partir de Debian Etch para lenny (g ++ (Debian 4.3.2-1.1) 4.3.2 ) No entanto eu tenho o mesmo problema em um sistema Ubuntu com o mesmo g ++.
Aqui está a parte relevante da minha classe matriz:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
}
}
E a "implementação":
using namespace Math;
std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {
[...]
}
Este é o erro dada pelo compilador:
matrix.cpp: 459: erro: 'std :: ostream & Math :: Matrix :: operator << (std :: ostream &, const Math :: Matrix &)' deve tomar exatamente um argumento
Estou um pouco confuso com este erro, mas mais uma vez o meu C ++ tem obtido um enferrujado pouco depois de fazer lotes de Java esses 6 meses. : -)
Solução
Você declararam sua função como friend
. Não é um membro da classe. Você deve remover Matrix::
da implementação. meios friend
que a função especificada (que não é um membro da classe) podem acessar variáveis ??de membro privadas. A maneira como você implementou a função é como um método de instância para a classe Matrix
que é errado.
Outras dicas
Apenas avisando sobre uma outra possibilidade: Eu gosto de usar definições amigo para isso:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
[...]
}
};
}
A função será direcionado automaticamente para o Math
namespace circundante (mesmo que sua definição aparece no âmbito dessa classe), mas não será visível a menos que você chamar operador << com um objeto Matrix que fará argumento pesquisa dependente achado que definição operador. Que às vezes podem ajudar com chamadas ambíguas, já que é invisível para outros fins que Matrix tipos de argumentos. Ao escrever a sua definição, você também pode se referir diretamente a nomes definidos em Matrix e para a própria Matrix, sem qualificar o nome com alguns possivelmente longo prefixo e fornecendo parâmetros do modelo como Math::Matrix<TypeA, N>
.
Para adicionar a resposta Mehrdad,
namespace Math
{
class Matrix
{
public:
[...]
}
std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}
Na sua implementação
std::ostream& operator<<(std::ostream& stream,
const Math::Matrix& matrix) {
matrix.print(stream); //assuming you define print for matrix
return stream;
}
Assumindo que estamos a falar de sobrecarga operator <<
para todas as classes derivadas de std::ostream
para lidar com a classe Matrix
(e não sobrecarregar <<
para a classe Matrix
), que faz mais sentido para declarar a função de sobrecarga fora do namespace Math no cabeçalho.
Use uma função amigo apenas se a funcionalidade não pode ser alcançado através das interfaces públicas.
Matrix.h
namespace Math {
class Matrix {
//...
};
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);
Note que a sobrecarga de operador é declarado fora do espaço de nomes.
Matrix.cpp
using namespace Math;
using namespace std;
ostream& operator<< (ostream& os, const Matrix& obj) {
os << obj.getXYZ() << obj.getABC() << '\n';
return os;
}
Por outro lado, se a sua função de sobrecarga faz necessidade de ser feito um amigo ou seja, precisa de acesso a membros privados e protegidos.
math.h
namespace Math {
class Matrix {
public:
friend std::ostream& operator<<(std::ostream&, const Matrix&);
};
}
Você precisa incluir a definição de função com um bloco de namespace em vez de apenas using namespace Math;
.
Matrix.cpp
using namespace Math;
using namespace std;
namespace Math {
ostream& operator<<(ostream& os, const Matrix& obj) {
os << obj.XYZ << obj.ABC << '\n';
return os;
}
}
Em C ++ 14 você pode usar o modelo a seguir para imprimir qualquer objeto que tem uma T :: print (std :: ostream &) const; membro.
template<class T>
auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os)
{
t.print(os);
return os;
}