Przeciążanie operatora klasy <<

0

Witam

Stworzyłem klasę i chciałbym aby przeciążyć jej operator - chodzi mi o " << "
Szukałem informacji ale mimo różnych kursów/poradników i instrukcji nie za bardzo zrozumiałem jak to zrobić dla operatora w kasie.
Różne operatory już przeciążałem ale z tym nie mogę sobie poradzić.

class Logger
{
public:
    Logger();
    void operator <<(std::string);///wiem ze tak to nie powinno wyglądać ale próbuje różne kombinacje alpejskie ;(
};
Logger::Logger()
{

}

void Logger::operator <<(/*Dziwna nazwa typu argumentu - to zostało wygenerowane przez Qt Creator */ std::__cxx11::string _str)
{
    ///body
}
 

Efekt który chciałbym uzyskać to mniej więcej taki zapis.

#define LOG_WARN "[WARN]"
int main()
{
Logger << LOG_WARN << "Program has been initialized succesfully";
}

Output: "[WARN] Program has been initialized succesfully"

Czy możecie mi pokazać jak mogę przeciążyć operator << tak żebym mógł stosować taki zapis jak powyżej ?

0

Po pierwsze musisz odróżniać obiekt od klasy. Jeśli Logger to klasa to Logger << LOG_WARN << "" nie ma żadnego sensu.

Nazwę argumentu popraw na zwykłe std::string (i prawdopodobnie chcesz przyjmować argument przez const& a nie przez kopię).

Logger log;
log << "foo";

Wtedy powinno działać

1
class Logger
{
public:
    Logger& operator<<(const string&);
};

Logger& Logger::operator<<(const string& msg)
{
    cout << msg;
    return *this;
}

int main()
{
    Logger logger;
    logger << "WARN" << " whatever";
}

Tylko że tak się zazwyczaj nie używa operator<<. Tego operatora się używa zazwyczaj ten sposób:

Logger logger;
cout << logger;

Żeby to było możliwe musisz albo implentować operator<< jako metodę klasy ostream (czego nie możesz zrobić) albo jako funkcję "globalną", która przyjmuje 2 parametry

ostream& operator<<(ostream& os, const Logger& logger)
0

@twonek - masz rację ale chciałbym w swojej aplikacji mieć możliwość logowania zdarzeń do klasy która by wyświetlała informacje na ekranie i na żądanie zapisywała na dysku.

Dlaczego nie mogę zapisać do klasy Logger w ten sposób:

Logger log;
log << "Program" << " has been started";

Dostaje całą litanię błędów których nawet nie ma co wklejać.

class Logger
{
public:
    Logger();
    std::string& operator <<(const std::string &);
};
Logger::Logger()
{

}

std::string& Logger::operator <<(const std::string & _str)
{
    std::cout << _str;
}

PS: Coś podobnego zrobiono dla klasy sf::Packet w bibliotece SFML.
Mozna było wsadzać informację do pakietu sieciowego mniej więcej tak:

sf::Uint16 x = 10;
std::string s = "hello";
double d = 0.6;

sf::Packet packet;
packet << x << s << d;
0
log << "Program" << " has been started";

to inaczej

log.operator<<("Program").operator<<(" has been started")

Żeby drugie wywołanie się udało, to pierwsze musi zwrócić obiekt (w tym przypadku najlepiej referencję) typu Logger. Popatrz uważnie na kod w moim pierwszym poście.

0

Wielkie dzięki @twonek
Właśnie zrozumiałem dlaczego operator<< sf::Packet z biblioteki SFML zwraca referencje do obiektu typu sf::Packet

Packet& operator <<(const String& data);

http://www.sfml-dev.org/documentation/2.4.0/Packet_8hpp_source.php

Myślicie że jest sens takich kombinacji jak ja tu robię, czy właśnie lepiej stworzyć dedykowaną metodę np report(const std::string&) tak aby użycie wyglądało:

Logger::report("Program has been started")

Innymi słowy w jaki sposób są robione klasy do logowania zdarzeń w aplikacjach z którymi się zetknęliście ?

PS: Wiem że aby użycie Logger::report .... było możliwe moja klasa musi mieć metodę report(std::string) statyczną

0

W tym przypadku to nie jest taki zły pomysł. Na pewno upraszcza zapis w przypadku wołań łańcuchowych.

1 użytkowników online, w tym zalogowanych: 0, gości: 1