-
вопрос такой, как в крестах наиболее корректно симулировать ADT ? То есть, надо иметь такой тип: сообщение, которое может быть либо сообщением А, либо Б, либо В и у каждого набор параметров
Replies (56)
-
@segfault, Первое решение это базовый класс, три наследника и даункаст или виртуальные методы реализующие все необходимые функции над твоим типом сообщения. На гугл забей. Этот метод очевидным образом плох поскольку любой четвёртый наследник базового класса тоже валиден.
Второй вариант — тип-перечисление. Если коротко, то возьми boost::variant./9 · Reply -
@segfault, Визитор это ж просто паттерн, а даункаст это механизм языка. Или что-то поменялось за это время?
-
@SannySanoff, нет, этот просто паттерн можно просто применить чтобы избавиться от даункаста и добавить проверки на стадии компиляции
juick.com gist.github.com -
@segfault, Твой вариант офигительно запутанный и неочевидный. Имело смысл либо определить в базовом классе интерфейс и реализовывать его в наследниках, либо… если тебе нужен «паттерне-матчинг» то без даункаста ты всё равно ничего не сделаешь. Но вообще тебе скорее всего нужен variant.
-
@segfault, Да какой же это тогда ADT? Я могу ADT засунуть в switch в любом месте, а тут даже контекст вызова теряется, или его надо специально параметром объявлять.
Негодно. -
@ndtimofeev, без даункаста как раз сделаю, уже сделано же, функция acceptMessage принимает указатель на Message и без даункастов обрабатывается нужное сообщение, плюс, если передам сообщение, которое визитор не обрабатывает, то будет ошибка компиляции.
-
@segfault, Это вариант не будет работать, если ты получишь указатель на базовый класс.
-
@SannySanoff, фигачишь новый наследник MessageVisitor и засовываешь свой контекст в него.
-
@segfault, В классе MessageVisitor нет метода определённого для типа Message. Он работает только тогда когда тебе известен тип сообщения в момент компиляции.
-
@ndtimofeev, смотри функцию acceptMessage, она принимает именно его
-
@ndtimofeev, не можешь за одним подсказать, как убрать уродство типа
MoveMessage m(20, 20);
MoveMessage m2(10, 10);
StopMessage m3;
acceptMessage(&m);
acceptMessage(&m2);
acceptMessage(&m3);
?
Надо передать указатель блин, и не охота создавать дурацкие временные объекты -
@ndtimofeev, ну да, m1, m2, m3 они же на стеке создаются, и мы передаем указатель на них в acceptMessage, хочется писать в одну строку типа
acceptMessage(MoveMessage(20, 30)); -
@segfault, Ну коли как лямбду, то может и сойдет.
А чтобы без указателей, объявляй параметры как &argName и пользуй temporary. -
@segfault, А какая разница? (хотя я на плюсах не пишу давно, мне кажется что референсы это те же указатели только сбоку)
-
@SannySanoff, Как лямбду не получится. Разве что передавать лямбдами в MessageVisitor обработчики для разных конструкторов.
-
@ndtimofeev, Да, вроде жабные анон классы тупая вещь, а поди ж ты. Думал лямбды как-то можно заюзать прямо как их в жабе, хотя естественно нет, в лямбдах же только одна точка входа.
-
@SannySanoff, проблема в том что когда принимаешь указатель, то он может быть как указателем на экземпляр, так и указателем на наследника класса, а ссылка должна быть конкретного типа, потому что у нее семантика объекта а не указателя. Очень хуевое техническое решение смешивать логику указатель/объект и конкретный класс/любой наследник ясчитаю. Чтобы принять в функцию любого наследника я должен принять указатель, и в этом жопа, потому что указатели надо либо выделять/освобождать, либо давать как ссылку на объект из стека
-
@SannySanoff, можно сделать универсальный супер мега визитор, регистрирующий коллбэки на каждый тип сообщения, и метод visit для каждого типа сообщения путь дергает нужный коллбэк, если тот зарегистрирован, или ничего не делает, если коллбэка нет.
-
@segfault, ну да, и по очереди навешивать коллбэк за коллбэком
-
@segfault, А что мешает сделать у базового класса набор виртуальных методов принимающих колбеки разных типов? И не страдать фигнёй.
-
@ndtimofeev, Ну вот пришел тебе Message*
и как ты теперь узнаешь какой метод вызвать? У них же будут разные сигнатуры как я понял, то есть тоже самое что тупо много разных методов -
@segfault, Точно также как и здесь. В конкретном классе передаёшь в колбек this.
-
@ndtimofeev, не понял, то есть в каждое сообщение передавать коллбэки на все случаи жизни, а потом одним виртуальным методом вызывать нужный ? И так при обработе каждого сообщения ?
-
@segfault, А ты сейчас в каждый визитор передаёшь сообщения на все случаи жизни. В чём разница?
-
@dr-Chaos, ну понятно, что придется менять базовый класс, а значит и ВСЕ наследники, но ведь это и есть ADT компилятор тебе покажет где там не хаватает методов в наследниках чтобы обработать новые типы сообщений корректно (или проигнорировать явно), да, нужен доступ к сиходному коду, зато безопасненько.
-
@segfault, Не понял тебя. Ты создаёшь по визитору на контекст.
-
@ndtimofeev, ну да, контекст то можно создать в инициализации, а потом принимать сообщения одно за другим
-
@ndtimofeev, ну прикольно, только у тебя не паттернматчинг, вызов огромного числа методов, в то время как с визитором только два перехода по указателю и вызов метода
А разве список освобождает указатели? при выходе из майн вызовутся деструкторы для его элементов ?