Базовый курс C++ (MIPT, ILab). Lecture 9. Множественное наследование

Поділитися
Вставка
  • Опубліковано 10 лис 2024

КОМЕНТАРІ • 47

  • @Scherbakov
    @Scherbakov 2 роки тому +10

    Великая благодарность за ссылки: "предыдущая лекция" и "следующая лекция"!! Также очень удачно подобраны размеры окон на видео. Очень удобно и на мониторе и на телефоне смотреть. Материал кайф!

    • @tilir
      @tilir  2 роки тому +8

      Кстати меня за эти ссылки критиковали. Типа (1) есть же плейлисты и (2) можно же делать всплывающую подсказку в конце.
      Но я сам отсмотрел тонну образовательных видео и мне всегда чего-то такого не хватало.

  • @ОлегВасилевский-ш8щ

    Огромная благодарность!

  • @ufabiz
    @ufabiz 3 роки тому +2

    std::regex у нас начиная с c++11. Я в последний раз пробовал его году в 17-м. По скорости был, мягко говоря, не очень. Тогда для себя решил, что Re2 -- гораздо лучше.
    Вообще на сегодняшний день вполне можно было бы сделать regex, строящий автомат в CT. Вроде бы уже всё для этого есть.
    И есть языки, в которых так и сделано. Это очень удобно. В debug сборке regex строится в рантайме, в release в компайл тайме.

    • @tilir
      @tilir  3 роки тому +1

      Так хм... flex это и делает: строит всё во время компиляции. Делать такое внутри языка через constexpr или шаблоны можно (я видел доклад на cppcon по ct regex), но это будет занимать годы времени компилятора. Я как то созерцал проект, куда от самонадеянности затащили boost::spirit и это было очень долго, очень плохо и с очень плохой диагностикой.

  • @egoreremeev9969
    @egoreremeev9969 3 роки тому +4

    1:00:00 "Задана операция конкатенации, которая делает из строк группу"
    Ну у строк не определено понятие "обратной строки" которая делает из строки пустую, поэтому скорее не группа а полугруппа

    • @tilir
      @tilir  3 роки тому +2

      Да, спасибо. Скорее даже не полугруппа, а моноид. Внесу в errata.

  • @EugeneS88-RU
    @EugeneS88-RU Рік тому

    9:29 в C# с недавнего времени разрешено объявление методов с их телом, считается поведением по умолчанию, т.е. если не будет реализован метод в наследуемом классе/ структуре то поведение будет то, которое в написано интерфейсе. Можно сказать, что это как раз наследование реализации. Скоро можно будет себе отстреливать не только ноги

    • @tilir
      @tilir  Рік тому +2

      Это похоже на семантику extern inline из C99.
      P. S. этот канал явно не предназначен для обсуждения C#

  • @redf1sh
    @redf1sh 2 роки тому +1

    Нашёл на своём гитхабе лексер и парсер от cool, это было 5 лет назад. Но курс так и не окончил. Тогда курс iLab вёл парень, который нас агитировал идти в Tarantool. Забавно, но на гитхаб распознаёт cool как отдельный язык и есть даже какая-то подсветка синтаксиса для него. Кто знает, может и для ParaCL добавят :)

    • @tilir
      @tilir  2 роки тому +1

      Да пять-шесть лет назад меня на айлабе еще не было я ещё был в софт машинс вероятно. Я думаю кул они брали 1в1 из Стэнфордовского курса. Парасил немного более локальная штука.

  • @samolisov
    @samolisov 3 роки тому +2

    39:12 "мы выводим где лежим мы сами и где лежит наше d", немного оговорились, не где лежит наше d, а натурально само d.
    Не понятно почему адрес наследника не совпал с адресом одного из предков, из-за указателя на собственную таблицу виртуальных функций? Но разве при обычном, одиночном наследовании не так же? Тоже ведь есть таблица виртуальных функций и получается адрес объекта-наследника не будет совпадать с адресом зашитого внутри базового класса, но указатель на наследника будет приводиться к указателю на базовый класс и без static_cast.
    Upd: а, понял, адрес совпадет с Filler'ом.

  • @ddvamp
    @ddvamp 2 роки тому +1

    Оффтоп(?) 54:35 Так ли это, что всегда можно избежать? Есть же исключительные ситуации, которые невозможно обработать. Например невозможность захватить мьютекс, или банально память кончилась. Тогда на main catch(...) вешать? Или к примеру использование внутри "noexcept части программы" тех же аллокаций, мьютексов и т.д., с невозможностью преодоления terminate (или это ошибочный дизайн?). Я даже с интернетом не смог разобраться.
    Может быть вы знаете какие-то доклады на тему аварийного завершения программы и освобождения ресурсов?

    • @tilir
      @tilir  2 роки тому +1

      Вы не должны внутри noexcept части программы использовать что-то что может бросать исключения.
      Вы не должны где бы то ни было вызывать abort или std::terminate.
      В рамках базового курса любое другое проектирование плохое. Учить чему-то другому это преступление. Если вы пишете библиотеку и у вас кончилась память вы должны поймать bad_alloc и вернуть вызывающему коду что у вас кончилась память, отпустив все ресурсы и всё остальное.
      И да, я знаю, что есть программы которые спроектированы иначе (например LLVM считает возможным делать аборт по фатальной ошибке и это было моей личной головной болью три года в Интеловском графическом драйвере, который пытается использовать LLVM как библиотеку и этим нарушает L0 спек по каждому аборту). Это ничего не меняет. Проектировать так чтобы можно было вызвать аборт это всегда, несомненно и совершенно точно ошибка. Вы должны освободить все ваши ресурсы и вернуть управление, точка. Если для этого надо вставить catch в main, сделайте это.
      Это не обсуждается.

  • @ДмитрийСадков-е8ц
    @ДмитрийСадков-е8ц 2 роки тому +1

    мелькая опечатка на слайде 78, самая нижняя строка
    IOFile f; // вызовет File(smth3)
    заменить на
    IOFile f; // вызовет File(smths3)

  • @alexskatkov2124
    @alexskatkov2124 3 роки тому +2

    Добрый вечер!
    1:00:35. Это не группа. Нет обратных элементов.

    • @tilir
      @tilir  3 роки тому

      Спасибо, но вы второй =) Это уже есть в errata. Вот за что я люблю свою аудиторию, группу с моноидом тут перепутать никто не даст ))

  • @АндрейШерстобитов-в8д

    Большое спасибо! Очень интересно послушать лекцию по автоматам, но в описании не нашел

    • @tilir
      @tilir  3 роки тому +1

      На этом же канале: ua-cam.com/video/M2XqgaJXjhM/v-deo.html

  • @vividbw
    @vividbw Рік тому

    На диаграмме классов на 32 минуте перепутаны направления стрелочек наследования и композиции. Ромбовидный наконечник идёт на стороне объекта-агрегата, треугольный наконечник идет со стороны родительского класса

    • @tilir
      @tilir  Рік тому +2

      Первый раз это замечание появилось в комментариях к этому видео год назад, но всё равно спасибо за наблюдательность ))

    • @vividbw
      @vividbw Рік тому

      @@tilir , все равно, спасибо за ваш курс, очень систематически рассказываете.

  • @ddvamp
    @ddvamp 2 роки тому +1

    Прошу прощения за придирку относительно 47:20, понимаю, что суть объяснения касается typeid, но всё же динамический тип есть у каждого объекта, и в случае с указателем он совпадает со статическим. Простой пример несовпадения статического и динамического типов без полиморфного класса, когда мы инспектируем объект как массив char-ов. На мой взгляд корректнее говорить про полиморфный класс, как описано в стандарте [expr.typeid]#3,#4
    P.S. Посмотрел лекции предыдущего и следующего годов, и там не было так сказано. Возможно это неудачная формулировка?

    • @tilir
      @tilir  2 роки тому +1

      Да, я тут всегда балансирую между корректностью и понятностью. Конечно методически правильно считать что динамический тип есть только если есть vtbl. Но формально да, есть у всех.

  • @Николай-ы6к5ь
    @Николай-ы6к5ь 3 роки тому +2

    Здравствуйте. Иногда на в примерах замечаю, что в main идёт выделение памяти, но нет освобождения её. Это корректное написания кода? Во всех ли случаях ОС освободит память после завершения программы?

    • @tilir
      @tilir  3 роки тому +2

      Это некорректно. Память за собой надо всегда освобождать. Но я часто экономлю место на слайдах если это не критично. Ну и да, ОС конечно всё освободит, но это не отменяет того, что вы тоже должны это сделать.

    • @randomcraft2345
      @randomcraft2345 3 місяці тому

      Вставлю 5 копеек.
      ОС то освободит память, однако иногда пишутся такие программы, которые должны работать постоянно без перебоя. В таких случаях программа завершают редко, и ровно так же редко освобождаются утечки, а в промежутках всё больше и больше накапливается утёкшая память. Если программа год без выключения простояла (та же ОС) - скорее всего работа серьёзно замедлилась, правда значит и утекает по чучуть; а если много - программа может сама завершиться из-за исчерпания доступных ресурсов, и даже не обязательно, что пройдёт хотя-бы день. По этому нет нам лафы), если только не перейти на язык со сборщиком мусора. Освобождение памяти, не смотря на страховку ОС, не просто эстетика, перфекционизм, догматизм, но в первую очередь стабильность работы, т.к. страхует ОС только после отработки программы, а не во время (если мы говорим про память), и чем дольше должна работать программа - тем важнее эта стабильность.
      Понимаю, что за 2 года могли уже сами узнать это. Пишу в целом для интересующихся.

  • @niklkelbon3662
    @niklkelbon3662 2 роки тому +1

    Так а почему бы this не работать в случае из начала видео? Ожидается указатель на тип, который является моей базой, так привожу свой this к указателю на мою базу и всё, либо более явно кастую, по моему никаких проблем там не должно произойти.
    Даже если там будут работать с объектом по указателю, то он уже сконструирован

    • @tilir
      @tilir  2 роки тому +1

      Я не нашёл контраргументов. Если бы я их нашёл, я бы их упомянул. Мне просто не нравится эта идея. В принципе если там не делать дополнительную косвенность, а оставить this, ничего особо не поменяется, множественное наследование изобретено, идём дальше. Можете рассматривать избавление от this здесь как необязательное эстетическое усложнение.

  • @babichfx
    @babichfx 3 роки тому +2

    42:30 Я написал 4 класса, 2 и 3 наследуют виртуально 1й, 4й наследует второй и третий; Создал объект 4го и вывел адрес с полем. Потом сделал статик каст на 2й и так же вывел адрес с полем. Потом сделал обратный каст из второго на 4й и вывел поле.
    Каждый раз адрес оставался одним и тем же! Хотя поле выводилось верно. Результат:
    0x7fb1afc057a0 1
    0x7fb1afc057a0 5
    0x7fb1afc057a0 1
    Почему так? Ведь статик каст в лекции выдает ошибку при наличии виртуального наследования, а у меня нет. И адрес на выводе не меняется.

    • @tilir
      @tilir  3 роки тому +2

      static_cast для ошибки должен идти через виртуальную базу. Если он не проходит через смерженные таблицы, то с ним всё ок.
      Например вот пример со структурой похожей на вашу: я создаю объект типа D через виртуальную базу и он ломается: godbolt.org/z/KT7zWTz6K
      Но замените там в 20-й строчке A* на D* и он пройдёт без ошибок т.к. будет идти только через статически известную компилятору часть.

    • @babichfx
      @babichfx 3 роки тому

      @@tilir Тонко! У меня получилось добиться ошибки в своем коде, спасибо.
      В практическом смысле это означает что мы, например, не сможем передать объект по базе в функцию и там специализировать его. Например так:
      void foo(A & pa){
      B *pb = static_cast(pa);
      std::cout

  • @ykrylov1969
    @ykrylov1969 3 роки тому +2

    Здравствуйте. У вас на диаграмме классов UML, для демонстрации виртуального наследования, IMHO неправильно проставлены значки наследования: исходя из вашей диаграммы класс Х это базовый класс для D1 & D2, а никак не наоборот.

    • @tilir
      @tilir  3 роки тому +2

      Да всегда с этим путался. Надо будет перерисовать.

    • @ykrylov1969
      @ykrylov1969 3 роки тому +1

      Запомнить можно легко используя правило: широкий конец стрелки в сторону расширенного класса, то есть класса-наследника :)

    • @tilir
      @tilir  3 роки тому +2

      Отлично )) Обожаю дурацкие мнемонические правила. Добавлю это в свою лекцию по solid (будет позже в этом курсе).

    • @ykrylov1969
      @ykrylov1969 3 роки тому

      Я тоже кое что запомнил из ваших лекций: "Акисление на аноде". Такое не забыть:)

    • @ЮрийПопов-л6я
      @ЮрийПопов-л6я Рік тому

      Тоже бросилось в глаза. И даже тупанул на задачке не мог понять что не так потом сообразил - стрелки

  • @jopa19991
    @jopa19991 3 роки тому +1

    Великолепная лекция! Задание доступно только студентам? Было бы интересно изучить.

    • @tilir
      @tilir  3 роки тому

      Вы о каком именно задании?

    • @jopa19991
      @jopa19991 3 роки тому

      @@tilir парасил, если я правильно расслышал

    • @tilir
      @tilir  3 роки тому +3

      Да я пока спеку не выложил. Но вообще сесть и написать свой компилятор любого C подобного языка это очень полезно и моя проверка вам там не особо нужна. Просто сделайте так чтобы он работал.

  • @user-jvg4k8m77s
    @user-jvg4k8m77s 2 роки тому +3

    Стало любопытно: а почему виртуальные функции и виртуальное наследование вообще называются виртуальными? У понятия виртуальности как-то много определений, некоторые из них подходят.
    Склоняюсь к тому, что «виртуальный» в C++ означает «как настоящий» или «имитированный», то есть выглядящий полностью реальным и обычным, но на самом деле являющийся чем-то совершенно другим.
    - Вызов виртуальной функции выглядит вполне обычным вызовом метода для базы, но на деле неизвестно, какая функция скрывается за этой маской.
    - Работа с виртуальной базой кажется нормальной, будто базовая часть структуры находится на своём законном месте, а не где-то за указателем.
    Интересует, потому что хочется связать идею названия с идеями реализации и практического применения.

    • @tilir
      @tilir  2 роки тому +1

      Читайте "виртуальный" как "требующий специальной поддержки в конструкторе". В случае виртуальной функции конструктор заполняет её вхождение в VMT, в случае виртуального подобъекта, записывает (на самом деле -- тоже в VMT) оффсет разделяемого региона. И то и другое он делает незаметно для программиста.

  • @СеменЦимбалюк-ф4л
    @СеменЦимбалюк-ф4л 2 роки тому +1

    1:10:00 даже заинтересовало, как будет выглядеть ДКА, решил построить, вроде получилось, но не такое уж оно и большое вышло. Даже проверил в работе, сравнил с regex - работает. Вот пару строк на случайном генераторе.
    bbabababbaabcbbbcbbbcbbccccbbc
    babaaababaaaaababbccccccccbbcc
    bbabaabbbababbabbccbbbbbccbccc
    bbabbbaaabcccbbbccccbcbcbccccc
    baaabbbabbabbabaabbbbcccbbccbb
    bbabbbbbaababcbcbcbcbbcbbbcbbc
    ababaabbbaaabbababccbbcbbbcccc

    • @tilir
      @tilir  2 роки тому

      Теперь можете потренироваться на выражении ((ab.*cd) | (ef.*gh)). Например abefcd подходит, а efefcd нет. Там получается очень красивый DFA.