Zadanie z przeciążaniem operatora strumieniowego

0

Witam,

Napotkałem problem podczas rozwiązywania zadań przed kolokwium z Programowania Obiektowego w C++ .
Na początek wstawię poniżej nagłówek klasy, której dotyczy zadanie.

#ifndef STRINGLIST_H
#define STRINGLIST_H
#include <list>
#include <string>
#include <iostream>
#include <utility>

class StringList
{
private:
    std::list<std::string> l;
    std::list<std::string>::iterator current_line; // moje pomysły, raczej zły tok myslenia
    int current_word = 0; // to rowniez

public:
    StringList operator+(const std::string &s);
    StringList operator-(const std::string &s);

    std::list<std::string> getList();

    friend std::ostream& operator<<(std::ostream &os, const StringList &sl);
    friend std::ostream& operator<<(std::ostream &os, const StringList &sl);

};

std::ostream& operator<<(std::ostream &os, const StringList &sl);
std::ostream& operator<<(std::ostream &os, const StringList &sl);

#endif // STRINGLIST_H

No i tresc zadania

Zadanie 4.
Zaprogramuj dla klasy StringList wyjściowy operator strumieniowy, którego kolejne wywołania tego operatora będą skutkować przepisaniem na strumień jednego, kolejnego wyrazu z napisu. Jeżeli osiągnięty zostanie koniec pierwszego należy przejść do kolejnego itd. W przypadku dojścia do końca listy działanie jest nieokreślone.

No i mam problem jak podawać na strumien po jednym wyrazie? Ok, gdyby trzeba było podać wszystkie na raz nie ma problemu, robie sobie 2 pętle i wszystko gładko działa. Ale w jaki sposób zapamiętywać w ktorym miejscu skonczyłem (tzn który wyraz powinien byc rzucony gdy wywołamy kolejny raz operator << ) ?
Podjąłem jakieś próby ze zmiennymi pomocniczymi : iterator wskazujacy na linie i int wskazujacy na numer słowa które powinno byc wyswietlone w dalej linii, ale wydaje mi się że nie tędy droga.
Będę wdzięczny za wszelkie wskazówki.

0

może naprowadzeniem na to jak podejsc do problemu bedzie kolejne zadanie?

Zadanie 5.
Zmodyfikuj operator z poprzedniego zadania tak, aby w przypadku dojścia do końca listy rzucany był wyjątek std::out_of_range, ale następne wywołanie tego operatora powodowało rozpoczęcie odczytywania od początku.

1

naklepałem coś na szybko, przeanalizuj i wyciągnij wnioski

struct test
{
    std::istringstream input{ "To jest tekst." };
    friend std::ostream& operator<<(std::ostream &os,  test &sl);
};

std::ostream &operator<<(std::ostream &os,  test& a) {
    std::string data;
    a.input >> data;
    os<<data;
    return os;
 }
// w int main()
 test moj_test;
   std::cout << moj_test << "\n";
   std::cout << moj_test << "\n";

edit:
a co do samej listy to iteratory.

0

Tylko jeszcze problem z konstruktorem kopiującym jak mam stringstream jako pole składowe klasy... Kompilator generuje mi błąd jak konstruktora kopiujacego nie napiszę ręcznie, a nie wiem jak napisac, aby kopiował także stan obiektu typu stringstream. Konstruktor kopiujący tutaj sie wykonuje

StringList StringList::operator+(const std::string &s){
    for(const auto &v : l)
        if(v == s)
            return *this;

    StringList result(*this); //tu pewnie dziala konstruktor kopiujacy
    result.l.push_back(s);

    return result;
}
0

Tylko jeszcze problem z konstruktorem kopiującym jak mam stringstream jako pole składowe klasy...

Bo to jest strumień taki sam jak iostream. Trzymaj w klasie referencję do niego.

0
StringList::StringList(const StringList &other)
    : stream(other.stream.str())
{
    this->l = other.l;
    this->stream.seekg(other.stream.tellg());
    this->stream.seekp(other.stream.tellp());
    this->stream.setstate(other.stream.rdstate());
}

/home/piotrek/kolokwiumOOP/powtorzenie/stringlist.cpp:10: error: passing ‘const stringstream {aka const std::__cxx11::basic_stringstream<char>}’ as ‘this’ argument discards qualifiers [-fpermissive]
this->stream.seekg(other.stream.tellg());
^

Wie ktoś może dlaczego to generuje błędy?

0

#ifndef STRINGLIST_H
#define STRINGLIST_H
#include <list>
#include <string>
#include <iostream>
#include <sstream>

class StringList
{
private:
    std::list<std::string> l;
    std::stringstream stream;

public:
    StringList(const StringList &other);
    StringList operator+(const std::string &s);
    StringList operator-(const std::string &s);

    std::list<std::string> getList();

    friend std::ostream& operator<<(std::ostream &os, const StringList &sl);
    friend std::istream& operator>>(std::istream &is, const StringList &sl);

};

std::ostream& operator<<(std::ostream &os, const StringList &sl);
std::istream& operator>>(std::istream &is, const StringList &sl);

#endif // STRINGLIST_H
#include "stringlist.h"
#include <algorithm>

StringList::StringList(const StringList &other)
    : stream(other.stream.str())
{
    this->l = other.l;
    this->stream.seekg(other.stream.tellg());
    this->stream.seekp(other.stream.tellp());
    this->stream.setstate(other.stream.rdstate());
}

StringList StringList::operator+(const std::string &s){
    for(const auto &v : l)
        if(v == s)
            return *this;

    StringList result(*this); //tu pewnie dziala konstruktor kopiujacy
    result.l.push_back(s);
    stream << s;

    return result;
}

StringList StringList::operator-(const std::string &s){
    StringList result(*this);

    auto pos = std::find(l.begin(), l.end(), s);
    if(pos != l.end())
        result.l.erase(pos);

    return result;
}

std::list<std::string> StringList::getList(){
    return l;
}

std::ostream& operator<<(std::ostream &os, const StringList &sl){
    std::string word;
   // sl.stream >> word blad
    os << word;
    return os;
}
1

Jakbym dostał do "code review" kod, który pełnia wymagania tego zadania, to bym porządnie skrytykował autora.
Takie zachowanie StringList jest bardzo dziwne i nieoczekiwane i późniejsze czytanie kodu, który korzysta z takiego operatora jest bardzo nieczytelne trudne do zrozumienia i będzie prowadzić do błędów.
Są pewne standardy kodowania, których przestrzeganie pomaga czytać i rozumieć kod.

Taką funkcjonalność realizowałbym za pomocą klasy pomocniczej którą bym nazwał PrintNextOne lub coś w ten deseń.

Kod który spełnia to durne wymaganie:

// mutable std::list<std::string>::const_iterator current_line;

std::ostream& operator<<(std::ostream &os, const StringList &sl) {
     if (!os.good()) {
          return os;
     }
     if (sl.current_line == sl.l.end()) {
          os.setstate(std::ios::failbit);
          return os;
     }
     os << *sl.current_line;
     ++sl.current_line;
     return os;
}

Przy czym każda modyfikacja StringList musi ponownie ustawić wartość current_line by zapobiec UB.

0

a czy mogę dać jako zmienna prywatna w klasie w jakiś sposób zwykłego inta, który będzie wskazywał na numer słowa w aktualnej linii i go inkrementować w jakiś sposób mimo że mam stałą referencję w funkcji przeciazania operatora na const StringList &sl ?

0

A czy nie moznabyłoby tego zrobic w ten sposob?

std::ostream& operator<<(std::ostream &os, const StringList &sl){
    if(sl.wc_in_line == 0) sl.countWords();

    if(sl.current_word == sl.wc_in_line){
        ++sl.current_line;
        sl.current_word = 0;
        sl.wc_in_line = 0;
        sl.countWords();
    }

    os << "Current Line: " << *sl.current_line << " wc in line: " << sl.wc_in_line << " current word nr: " << sl.current_word << std::endl;

    std::istringstream iss(*sl.current_line);
    int word_nr = 0;
    std::string word;

    while(iss >> word){
        if(word_nr == sl.current_word){
            os << word;
            break;
        }
        ++word_nr;
    }

    ++sl.current_word;
    return os;
void StringList::countWords() const{
    std::istringstream iss(*current_line);
    std::string word;
    while(iss >> word)
        ++wc_in_line;
}

StringList StringList::operator+(const std::string &s){
    for(const auto &v : l)
        if(v == s)
            return *this;

    StringList result(*this); //tu pewnie dziala konstruktor kopiujacy
    result.l.push_back(s);
    current_line = l.begin();
    current_word = 0;
    wc_in_line = 0;

    return result;
}
class StringList
{
private:
    std::list<std::string> l;
    mutable std::list<std::string>::const_iterator current_line;
    mutable int current_word;
    mutable int wc_in_line;
    void countWords() const;
} .....

Tylko nie wiem dlaczego nie przechodzi mi do kolejnej linii

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