Loading...
Jovanna avatar Jovanna 186 Точки

C++ Advanced, 08_03_TypedStream - Някои детайли

Здравейте,

извинявам се, че питам пак за предишните задачи, но има някои детайли, които не разбирам и не мога да продължа напред докато не си ги изясня:

1/ защо полето не може да е  std::istream stream; ?

2/ Защо не можем да подадем в конструктора const референция към стринга?

3/ Какво връща this->   , Защо синтактсисът не е:  this->stream.operator>>(item).stream.good() 

class TypedStream {
protected:
    std::istringstream stream;     //ЗАЩО НЕ istream  ?
public:
    //TypedStream( const std::string& input) : stream(input) {}
    TypedStream( std::string input) : stream(input) {}             //ЗАЩО КОПИЕ ?

    virtual TypedStream<T>& operator>>(T& t) { return *this; }
    //virtual TypedStream<T>& operator>>(T& t) = 0;

    std::vector<T> readToEnd() {
        std::vector<T> v;
        T item;
//        while (this->stream.operator>>(item).stream.good()) {        //ЗАЩО ?
        while ((this->operator>>(item)).stream.good()) {

Благодаря.

Тагове:
0
C++ Programming
georgi.stef.georgiev avatar georgi.stef.georgiev 921 Точки
Best Answer

Здравей,

1) Може да бъде такова полето. Само че трябва да го инициализираш в инициализационния списък. А istream не се инициализира по string, съответно трябва да го инициализираш с istringstream, обаче stream-овете не поддържат copy операциите. Тоест проблемът е, че istream е базов клас, който не знае как да се инициализира със string, а ние това искаме, затова директно ползваме istringstream

2) Може да бъде const std::string& input параметъра, би следвало да се компилира и работи вярно

3) this е указател към текущия обект, върху който се вика метода - учили сме го това в C++ Fundamentals. Не можем да викаме this->stream.operator>>, защото така винаги ще викаме четенето както го познава istringstream. Ние не искаме това. Ние искаме наследяващите класове да определят как се случва четенето. Виж VectorStream класа. За да прочете Vector2D, той чете две променливи и след това създава Vector2D обект с тях като параметри на конструктора. Това istringstream няма откъде да знае да го направи. Затова TypedStream определя за себе си един виртуален operator>> , който не знае как да чете обекти от тип T, обаче наследяващите го класове могат да го override-нат за да четат обекти от техния си тип, защото те знаят какво е T и как се чете. Съответно TypedStream за да извика override-натата логика, вика своя operator>>, който е виртуален, защото така всъщност ще извика operator>> на наследяващия клас. Тоест TypedStream оставя отговорността за четенето на един обект на наследяващите класове, а се занимава с цялостната задача на четене на много такива обекти като в частта, която не му е известна (четенето на един обект) оставя наследяващия клас да определи. 

Представи си, че този TypedStream е музикално събитие. Събитието си има барабан (stream-а). Работата на събитието - в реалния свят работата на организатора на събитието - е да се обяви, да се заделят места, да се продадат билети, да се създаде атмосфера, да се определи начален час, и когато този начален час дойде, да стартира свиренето на музика. Обаче действието "стартиране на свиренето на музика" не се случва като организатора отиде и почне да пердаши барабана (T item; this->stream >> item) нали? Това което се случва, е че организаторът отива при барабаниста (virtual TypedStream& operator>>(...) ) и му казва на него "свири" (Т item; this->operator>>(item) ). Оттам нататък, барабанистът върши свиренето върху барабана, не организатора, въпреки че барабанът е собственост на организатора. Организаторът не знае как да свири на барабана, и затова вика барабанист и кара него да свири на барабана. Организаторът не се опитва той да свири на барабана си.

Оттам нататък, в зависимост от вида музикално събитие (IntStream, StringStream, VectorStream), барабанистът (override-а на operator>> в съответните наследяващи класове) може да свири рок, може да свири чалга, може да свири класическа музика и т.н. Това позволява на организаторът да си върши една и съща работа всеки път, а събитието да има различен характер, заради различната група, която свири - ако организаторът свиреше на барабана, щеше да трябва организаторът да знае всички възможни жанрове музика и да е музикант. Така, организаторът само се интересува от общите неща за всички събития, и вече като се конкретизира събитието да е рок, чалга или класическа музика, override-ващата група определя конкретно какво ще се случи.

Това е цялата идея на виртуалните методи и override-ването. Базовият клас се интересува от общите неща, но не знае конкретиката. Наследяващите класове определят конкретиката. Това позволява всякакво разширяване на функционалността, като просто се добавя различно наследяване и според това какво е наследено, се върши различна работа с една и съща базова логика.

Поздрави,

Жоро

3
Jovanna avatar Jovanna 186 Точки

Благодаря! 

това означава ли , че в случая от задача 2, след като базовият клас има поле istream, ще може да агрегира и от файлове, примерно, като му се подаде ifstream от main() и се разпишат съответните наследяващи класове ?

Поздрави!

0
georgi.stef.georgiev avatar georgi.stef.georgiev 921 Точки

Да, щом получава istream, а не конкретен stream - от main може да му подадеш и cin, и някой istringstream, и някой ifstream, ще работи. Това пак е заради наследяването, istringstream, ifstream и прочие наследяват istream, съответно нещо, което работи с istream, може да работи с който и да е stream за четене.

1
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.