Домашно [06. Full C++ OOP] - Въпроси и коментари
Тема за въпроси, свързани с домашното от 6-та лекция - Full C++ OOP, както и за коментари по задачите.
Започвам с въпроси относно 3-та задача:
1. "Write a SequencePrinter class, which has a pure-virtual print() method and a pure-virtual setSequence(const SequenceGenerator& sequence) method. Derive a SequencePrinterToString, SequencePrinterToFile, SequencePrinterToConsole class. Any class implementing setSequence(const SequenceGenerator& sequence) should change the sequence the current object work with, with the sequence passed-in from the method."
Условието предполага, че setSequence метода тябва да бъде имлементиран във всяко от трите разклонения на класа SequencePrinter. Какво различно се очаква да прави този метод във всеки от тези класове?
Ето как изглежда тази част в моята имплементация, като setSequence е идентичен във всички разлонения и е по-скоро излишен в този си вид (по-добре да не е виртуален, а дефиниран и имплементиран в SequencePrinter). changeSequence метода го добавих само за да мога да имплементирам setSequence като pure virtual, т.е. също би бил излишен при другото решение. Явно пропускам нещо.
2. Какво се очаква да прави print() метода в SequencePrinterToString класа?
Благодаря за отговора! :)
Имам решение на задачата, което изглежда удовлетворява условията, но честно казано не ми харесва - не блести с оригиналност, нито с гъвкавост, трябва да се внимава при използването му заради подводни камъни в имплементацията, а за капак има и части, които се повтарят в разклонените класове...
От коментара ти разбирам, че може би по-добро решение ще е SequencePrinterToString да наследява директно SequencePrinter, като има вариант и да се "сприятелят" частично или напълно, а SequencePrinterToFile и SequencePrinterToConsole да наследяват SequencePrinterToString (и без друго в настоящата ми имплементация те го използват за създаване на стринга, който пък още по-добре ще е да се рализира с << operator overload). Ако ми остане време от другите задачи, може да се върна и да я преработя.
Всъщност, най-големите ми проблеми с тази задача дойдоха заради изискването SequenceGenerator да бъде представен като референция в SequencePrinter класа, което направи невъзможно директното преизползване на един SequenceGenerator обект в няколко SequencePrinter обекта, както и е предпоставка за допускане на грешки. Определено не бих избрал този начин за имплементиране, ако трябва аз да правя дизайна с настоящите си знания, но както казах, има много неща, които все още не знам... :)
В тази задача има нещо като уловка и тя е именно този const SequenceGenerator & параметър. Ако полето ти в класа е референция, няма как да имаш setSequence() метод, защото след като една референция е инициализиране е невъзможно да я накараш да сочи към нещо друго - ако кажеш setSequence(someOtherGenerator), това няма да смени твоя printer да ползва друг generator, a просто ще презапише върху предишния generator този, който подаваш (т.е. все едно извън класа си присвоил на единия генератор другия).
Това, което аз бих направил в този случай, е да си направя полето в класа да е const SequenceGenerator *, вместо референция - понеже е pointer, мога да го карам да сочи към друго място, тоест мога правилно да имплементирам setSequence(). Също така, понеже имам pure-virtual клас, който трябва да наследя с няколко класа, които имат общо помежду си, ще си направя един общ базов клас за тях - SequencePrinterBase примерно:
Оттук нататък наследяваш SequenceGeneratorBase с класовете дадени в задачата, а метода го викаш ето така:
Но защо тогава да е референция, а не просто указател - само за да е уловка ли? Не. Понякога се ползва референция, за да е по-трудно да се допусне грешка с параметъра - ако е указател, лесно могат да ти подадат указател към произволна памет, cast-нат към съответния тип директно като викат метода. Когато е референция, на викащия му се налага поне да има някаква променлива предварително от някакъв тип. Разбира се, в C++ винаги може да ти подадат грешен параметър, но с този код ако някой неволно сгреши докато пише е малко по-вероятно да го хване компилатора. Не е напълно солиден подход и не се ползва много, но исках да ви срещна и с тази ситуация, защото в истинската работа би могло да ви се случи нещо подобно.
Поздрави,
Жоро
Благодаря за изчерпателния отговор!
С него плюс още едно преглеждане на видеото и демата от последната лекция, нещата почнаха да ми се нареждат.
Поздрави!