ah
#include "logic.h"
...
class A
{
friend ostream& operator<<(ostream&, A&);
...
};
logic.cpp
#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...
Kiedy kompiluję, mówi:
std :: ostream & logic :: operator << (std :: ostream &, A &) 'musi przyjmować dokładnie jeden argument.
Jaki jest problem?
c++
operator-overloading
iostream
Jak As
źródło
źródło
Funkcja znajomego nie jest funkcją
operator<<
składową , więc problem polega na tym, że deklarujesz jako znajomegoA
:friend ostream& operator<<(ostream&, A&);
następnie spróbuj zdefiniować ją jako funkcję składową klasy
logic
ostream& logic::operator<<(ostream& os, A& a) ^^^^^^^
Czy nie wiesz, czy
logic
jest to klasa, czy przestrzeń nazw?Błąd wynika z tego, że próbowałeś zdefiniować element członkowski
operator<<
przyjmujący dwa argumenty, co oznacza, że przyjmuje trzy argumenty, w tym niejawnythis
parametr. Operator może przyjąć tylko dwa argumenty, więc podczas pisaniaa << b
dwoma argumentami sąa
ib
.Chcesz zdefiniować
ostream& operator<<(ostream&, const A&)
jako funkcję niebędącą członkiem, na pewno nie jako element członkowski,logic
ponieważ nie ma ona nic wspólnego z tą klasą!std::ostream& operator<<(std::ostream& os, const A& a) { return os << a.number; }
źródło
Napotkałem ten problem w przypadku klas opartych na szablonach. Oto bardziej ogólne rozwiązanie, którego musiałem użyć:
template class <T> class myClass { int myField; // Helper function accessing my fields void toString(std::ostream&) const; // Friend means operator<< can use private variables // It needs to be declared as a template, but T is taken template <class U> friend std::ostream& operator<<(std::ostream&, const myClass<U> &); } // Operator is a non-member and global, so it's not myClass<U>::operator<<() // Because of how C++ implements templates the function must be // fully declared in the header for the linker to resolve it :( template <class U> std::ostream& operator<<(std::ostream& os, const myClass<U> & obj) { obj.toString(os); return os; }
Teraz: * Moja funkcja toString () nie może być wbudowana, jeśli ma być schowana w cpp. * Utknąłeś z jakimś kodem w nagłówku, nie mogłem się go pozbyć. * Operator wywoła metodę toString (), nie jest ona wstawiona.
Treść operatora << można zadeklarować w klauzuli friend lub poza klasą. Obie opcje są brzydkie. :(
Może nie rozumiem czegoś lub czegoś mi brakuje, ale samo zadeklarowanie szablonu operatora nie łączy się w gcc.
To też działa:
template class <T> class myClass { int myField; // Helper function accessing my fields void toString(std::ostream&) const; // For some reason this requires using T, and not U as above friend std::ostream& operator<<(std::ostream&, const myClass<T> &) { obj.toString(os); return os; } }
Myślę, że można również uniknąć problemów z tworzeniem szablonów wymuszających deklaracje w nagłówkach, jeśli używasz klasy nadrzędnej, która nie jest szablonem do implementacji operatora <<, i używasz wirtualnej metody toString ().
źródło
Jeśli zdefiniujesz
operator<<
jako funkcję składową, będzie ona miała inną zdekomponowaną składnię niż w przypadku użycia funkcji niebędącej składowąoperator<<
. Element niebędący członkiemoperator<<
jest operatorem binarnym, gdzie element członkowskioperator<<
jest operatorem jednoargumentowym.// 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; }
Więc… jak naprawdę je nazywasz? Operatory są pod pewnymi względami dziwne, wezwam cię do napisania
operator<<(...)
składni w twojej głowie, aby wszystko miało sens.MyObj mo; // Calling the unary operator mo << std::cout; // which decomposes to... mo.operator<<(std::cout);
Lub możesz spróbować wywołać operator binarny niebędący składnikiem:
MyObj mo; // Calling the binary operator std::cout << mo; // which decomposes to... operator<<(std::cout, mo);
Nie masz obowiązku zmuszać tych operatorów do zachowywania się intuicyjnie, gdy przekształcasz je w funkcje składowe, możesz zdefiniować
operator<<(int)
przesunięcie w lewo jakiejś zmiennej składowej, jeśli chcesz, zrozum, że ludzie mogą być nieco zaskoczeni, bez względu na to, ile komentarzy możesz pisać.Prawie na koniec mogą zdarzyć się sytuacje, w których obie dekompozycje dla połączenia operatora są prawidłowe, możesz mieć tutaj kłopoty, a my odłożymy tę rozmowę.
Na koniec zwróć uwagę, jak dziwne może być napisanie jednoargumentowego operatora składowego, który ma wyglądać jak operator binarny (ponieważ możesz sprawić, że operatorzy elementów członkowskich będą wirtualnymi ..... również próbując nie zdecentralizować i nie spuścić tej ścieżki ... )
struct MyObj { // Note that we now return the ostream std::ostream& operator<<(std::ostream& os) { os << *this; return os; } int value = 8; };
Ta składnia będzie teraz irytować wielu programistów ...
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");
Zwróć uwagę, dlaczego tutaj
cout
jest drugi argument w łańcuchu… dziwne, prawda?źródło