1. C++ / Говнокод #1852

    +55.5

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    class cCar: public GAMEPLAYER::cPlayerRef, public cScrObject,
    	public IspSetOnParkingPlace<GAMEPLAYER::cCar>, 
    	public IspCheckLoadedState<GAMEPLAYER::cCar>,
    //	public IspUseInitialPositioning<GAMEPLAYER::cCar>,
    	public IspSetVelocity<GAMEPLAYER::cCar>,
    	public IspTracetoPosition<GAMEPLAYER::cCar>,
    	public IspChangeVehicle<GAMEPLAYER::cCar>,
    	public IspChasePlayer<GAMEPLAYER::cCar>,
    	public IspRaceParamsPlayer<GAMEPLAYER::cCar>,
    	public IcallbackParked<GAMEPLAYER::cCar>,
    	public ALTERNATIVEK::cstore_this<GAMEPLAYER::cCar>
    { //... дальше не интересно

    Вот такой суровый cCar :)

    Запостил: generalgda, 16 Сентября 2009

    Комментарии (60) RSS

    • Это наследование?????????
      Ответить
    • харошая родословная)))
      Ответить
    • Это не говнокод... Это называется mixin...
      Попробуйте и вам понравится...
      Автору кода респект...
      Ответить
      • Миксин - да.
        Респект - рили!?
        Ответить
        • лопату этому господину.
          но с тех пор я действительно многое понял. когда миксины пишешь сам это хорошо и здорово, а когда приходится отлаживать их за кем-то, то это уже не так весело.
          в любом случае это не отменяет респекта автору.
          Ответить
      • Попробовал миксину, очень понравилось
        спсибо!!!
        Ответить
    • Можете почитать о пользе сдесь
      http://blog.gamedeff.com/?p=91
      Ответить
      • Это ещё какой говнокод. Во первых попробовали бы вы вот ЭТО отлаживать. То ещё удовольствие. Во вторых налицо попытка запихнуть в один класс кучу функциональности. Наследоваться нужно не чтобы переиспользовать, а чтобы быть переиспользованным. В Java очень просто запретили мутантов, который приведён в посте: запретили множественное наследование от классов. При проектировании - это типичные ошибки - сделать слишком глубокую иерархию наследования или использовать наследование взамен агрегации. Поверьте, игры, да и любые другие приложения, можно писать без таких монстров.
        Ответить
        • template<class T1, class T2>
          class A: private T1, private T2 {
          <here comes the code>
          };

          Такого потрясающего способа создавать полифункциональные классы ни в Java нету.
          Хотя код выше я признаю эксцентричным, но можно предположить, что это множественное наследование нужно для того, чтобы в разные маленькие функции-нечлены подсовывать "кусочки" интерфейса, которые представляют интерфейс-контракт именно с данной функцией.
          Ответить
          • Написанный вами код без проблем модифицируется в код, где A не наследует T1 и T2, а агрегирует их экземпляры. Ещё раз, наследоваться нужно чтобы вас переиспользовали (вызывали методы вашего класса через унифицированный интерфейс), а не вы кого-то (для этого и существует агрегация/композиция). Я допускаю, что бывают безвыходные ситуации, когда работаешь с legacy-кодом, который заставляет вас делать архитектурно стрёмные конструкции (вроде наследования, дабы получить доступ к какой-то скрытой в protected- секции функциональности). Наследование - самая сильная (после дружественности) зависимость между классами. А шаблоны предназначены для СТАТИЧЕСКОЙ параметризации кода, а не для извратов а-ля А. Александреску с наследованиями, списками типов и прочей магией. Код пишется не для машины, а для человека. Машине достаточно нулей и единиц.

            Такого потрясающего способа задания полифункциональных классов и не надо. Ни в C++, ни в C#, ни в Java ни где-то ещё. Есть другой потрясающий способ - реализовать пачку интерфейсов. Или заагрегировать в себе пару объектов и предоставить корректный доступ к ним через свои методы.
            Ответить
            • Можно всё переписать и без классов и быстрее работать будет.
              Эта штука очень изящно создаёт классы, которые нужны в данный конкретный момент из набора маленьких рабочих. Например: любой метод многомерной безусловной оптимизации с осями использует одномерный метод безусловной оптимизации и метод выбора осей. Нет смысла городить три объекта в место одного. Есть заранее написанные одномерные методы и методы выбора осей, они друг от друга не зависят, и один шаблон, который их объединяет. Я создаю один объект, указывая, что буду использовать, и никаких заморочек, всё за меня делает компилятор. Безумно удобно!
              Ещё может возникнуть ситуация, например, такая: вычисление магнитного поля одинаковое для различных счётных схем. Можно унаследовать открыто маленький класс, который поле вычисляет. И, далее, как маленький интерфейс подсовывать в нужном месте. Вот у Java будет реальная проблема, им придётся писать одно и тоже в трёх местах, потому что они не могут и отношение "является" частицей , и отношение "является создающим поле" выразить в одном классе. А я могу.
              Правда зачастую подобные вещи можно перепроектировать без множественного наследования. Но давайте рассуждать здраво, если это удобно в определённых случаях, то почему бы его не использовать? Это проще, чем ломать голову, над "изподвывернутой" архитектурой, которая обойдёт то, что физически очевидно.
              Ответить
              • "Вот у Java будет реальная проблема, им придётся писать одно и тоже в трёх местах, потому что они не могут и отношение "является" частицей , и отношение "является создающим поле" выразить в одном классе. А я могу."
                Угу, они тупыые!
                И конструкцию вида
                class Photon implements Particle, FieldGenerator
                никто из них написать не сможет, тут с вами поспорить сложно.
                А вы, конечно, сможете.
                Ответить
            • А при наследовании никаких интерфейсов предоставлять ненадо... Каждый класс сам предоставляет свой интерфейс... и использует любые интерфейсы которые знает, а если их нет в наследнике будет ошибка...

              краткий пример вышесказанного

              #define THIS static_cast<glue *>(this)

              template<class glue>
              class A
              {
              public:
              void DoA(){};
              };

              template<class glue>
              class B
              {
              public:
              void DoB(){ THIS->DoA() }
              };

              class C : public A<C>, public B<C>
              {

              };

              при этом может быть другой так и это будет уже другой класс

              template<class glue>
              class OtherA
              {
              public:
              void DoA(){};
              };

              class OtherC : public OtherA<C>, public B<C>
              {

              };

              никаких виртуальных вызовов слушателей делегатов и тп, все ошибки на этапе компиляции, одна проблема один класс - это все о чем пишут самые лучшие проектировщики...
              Ответить
              • плохой пример. годится только для использования в глубоком импле без выставления наружу.
                самые лучшие проектировщики пишут, что нужно именно так делать?
                Ответить
                • Это тяжело использовать в промежуточных фреймворках, только в конечных продуктах причем в большинстве случаев написанных с 0... очень легко подключаются сторонние либы (я подключал bullet, но у меня не было настолько чистой реализации миксина, так как физика подключалась в готовую кучу кода)...

                  Есть большой недостаток, это сильно растет время компиляции так как сложно что-то вынести в cpp файлы (хотя можно макрос THIS переписать немного по-другому и писать конкретные специализации шаблона, но это убьет все преимужества)

                  в общем это метод для тех кто не любит копипаст и функции типа

                  void SomeMethod()
                  {
                  m_obj->SomeMethod();
                  }
                  Ответить
              • Так себе решение. Очень удобно отлаживать ошибки компиляции
                Ответить
        • >Наследоваться нужно не чтобы переиспользовать, а чтобы быть переиспользованным.

          Это только твое личное мнение. Наследование реализации вместе с интерфейсом - это очень удобный механизм, которого иногда очень не хватает в C# или яве.

          >При проектировании - это типичные ошибки - сделать слишком глубокую иерархию наследования или использовать наследование взамен агрегации.

          Здесь не видно ни того, ни другого.

          >Поверьте, игры, да и любые другие приложения, можно писать без таких монстров.

          Можно, но тогда придется плодить пачку практически бесполезных методов, которые будут заниматься тупым перекидыванием вызовов внутрь включаемых реализаций.
          Ответить
          • > Наследование реализации вместе с интерфейсом - это очень удобный механизм, которого иногда очень не хватает в C# или яве.

            В терминах сишарпа это тогда и будет множественное наследование, и не интерфейс вовсе.
            Ответить
          • >Это только твое личное мнение. Наследование реализации вместе с интерфейсом - это очень удобный механизм, которого иногда очень не хватает в C# или яве.

            Про это обычно в ВУЗе на 2-ом курсе рассказывают. Ещё можете почитать А. Александреску + Герба Саттера: "Стандарты программирования на С++".
            Ответить
            • Множественное наследование релизации обычно не нужно, если в языке есть инструменты для делегирования
              Ответить
    • Проектировщикам необходимо оторвать руки
      Ответить
      • Похоже, там не было проектировщиков :-)
        Ответить
    • Не холиварте, а попробуйте... Это реально очень удобно... Данный клас мог вполне быть работоспособным при таком раскладе событий:

      class cCar: public GAMEPLAYER::cPlayerRef, public cScrObject,
      public IspSetOnParkingPlace<GAMEPLAYER::cCar>,
      public IspCheckLoadedState<GAMEPLAYER::cCar>,
      // public IspUseInitialPositioning<GAMEPLAYER::cCa r>,
      public IspSetVelocity<GAMEPLAYER::cCar>,
      public IspTracetoPosition<GAMEPLAYER::cCar>,
      public IspChangeVehicle<GAMEPLAYER::cCar>,
      public IspChasePlayer<GAMEPLAYER::cCar>,
      public IspRaceParamsPlayer<GAMEPLAYER::cCar>,
      public IcallbackParked<GAMEPLAYER::cCar>,
      public ALTERNATIVEK::cstore_this<GAMEPLAYER::cC ar>
      {
      }

      То есть ниединой строчки кода...
      Ответить
      • Очень смешно =]
        Но я и не думал холиварить.
        Просто generalgda думает, что "раз он благодетелен, то на свете не должно быть ни пирожков, ни пива".
        Ответить
    • У Александреску такое описывается: создание классов на основе стратегий. Так что тут все ок. Тем более этот код может быть сгенерирован каким-нибудь автоматическим конфигуратором игровых объектов.
      Ответить
      • Код писался человеком. И то что подход/код описывается у А.А. в книжке - это не значит, что подход правильный/хороший и что его надо использовать где попало.
        Ответить
        • Данный пример это идеальный случай применения этого кода...
          Советую понять суть метода и попробовать использовать, а потом уже называть говнокодом...
          Ответить
          • Вообще очень похоже, что каждый предок добавляет по методу в класс. Как-то это плохо выглядит... Хотя может это только на первый взгляд...
            Ответить
            • Это выглядит практически полным отсутствием копипаста (хотя говнокодеры не дремлют)... Весь функционал разносится по маленьким классам, то есть одна проблема - один класс...
              Естественно есть проблемы, это рост времени компиляции, не очень подходят стандартные и привычные для всех техники отладки (так как шаблонов полно), высокий порог вхождения... Новичкам очень трудно это усвоить, так как все поедено шаблонами и нестандартным мышлением, а стариков сложно убедить в достоинствах, так как они думают, что всегда правы... Поэтому здесь шаг влево шаг вправо и у тебя куча говнокода... А из достоинств очень мало кода, очень высокая утилизация кода (одинаковые функции теперь не надо копипастить, или шаблонизировать, это теперь отдельные классы), минимизация виртуальных функций, минимизация глубины наследования, что упрощает создание системы определения типа, так как в большинстве случаев класс однозначно идентифицирует одно число (самые хитрые используют для этого vtable) так как врятли разумно делать наследование глубиной больше 2 (похожие классы лучше делать почти одинаковым набором миксин)...
              Мне кажется такой код сложно ваять большой толпой, но я не пробовал, может быть и нетрудно.
              Ответить
              • Стариков сложно убедить в достоинствах, потому что они не приемлят такое использование наследования. Потому что в учениях страуструпа наследование - это способ построения ахуеть глубоких абстрактных иерархий объектов с полиморфной функциональность. У многих отписавшихся один вид данного кода вызывает батхерт. На самом деле, здесь наследование - это лишь способ расшарить функциональные части объектов. В данном примере базовые классы скорее всего даже не содержать виртуальных функций.
                По поводу отладки, я бы не сказал что тут будет сложно. Потому что при выполнии уже утвердились все инстансы шаблонов, так что для отладки есть информация.
                Ответить
                • :) Если я старик, то мой отец - Папа Римский. Страуструп, кстати, не очень круто писал за создание иерархий классов. Глубокие иерархии, чаще всего, являются архитектурным косяком. Исключение, разве что, ГУИ библиотеки.
                  Ответить
                  • ну это какбе "широкая" иерархия... так как родителям нет смысла от кого-то наследоваться...
                    Ответить
          • Я понимаю суть метода. Но пробовать использовать не буду. Мотивацию объясню метафорой: "Не нужно пробовать яд, чтобы понять, что от него умирают". Несколько утрированно, но мысль, думаю, донёс. Я не буду оспаривать право на существование такого подхода. Но не в таком виде и более того, не в С++. "Миксин" - конструкция из динамических языков программирования. Можно запользовать так: берём какой-нить динамический язак в качестве скриптового. Садим девелопера реализовывать кучу "действий" (тех самых методов из которых собирается класс, в приведённом говнокоде). Далее пишем редактор в котором дизайнер создаёт игровые объекты комбинируя доступные ему "действия". Выхлоп редактора - код на выбранном нами скриптовом языке. Вот это действительно power. А то что писали на gamedeff - жалкий костыль нифига не решающий проблему "пришёл геймдизайнер и сказал, что хочет мигающий шарик при ударе об стену". В "плюсах" миксин только и делает, что экономит время тайпинга. Взамен получаем, как вы уже сказали, увеличение время компиляци. Для мелких проектов не критично. Но для больших проектов - недопустимо. В проекте, где этот код пользовался была даже ситуация, когда компилятору не хватало памяти (!!!) при компиляции некоторых особо извращённых шаблонов. Но есть ещё минусы миксина: отсутствие code-completeon'a при написании кода шаблонных классов, сложность понимания кода (реализация класса разнесена по куче файлов, и даже интерфейса не видно, если посмотреть на его объявление), возможные грабли в виде ромбовидной иерархии и прочих радостей множественного наследования, перекомпиляция целой пачки файлов при изменении кода в шаблонном классе (от которого наследуемся) - шаблоны то в хедерах объявлены. Отсутствие виртуальных вызовов - не плюс. Во первых при агрегации их тоже не будет. И во вторых это не то на чём нужно экономить в верхнеуровневом коде.
            Ответить
      • Метапрограммирование, да
        Ответить
    • Это называется не знает о message-driven patterns. Если нужно обращаться к объекту по десяткам интерфейсов, стоит задуматься о реализации через посылки сообщений как это бывает в нормальных ООП-языках типа смолтока или ObjC.

      В ANSI C это делается за пару секунд и поддерживается проще некуда. А тут мозгошлёбства на три вагона ни для чего.
      Ответить
    • Эти ваши миксины и прочая ексть ни что иное как очередной костыль над кривой реализацией ООПа убогоньким С++. Признайте это, ущербные ;)
      Ответить
      • Какие ваши доказательства?
        Ответить
        • хотя бы приведенная выше конструкция :)
          Ответить
          • То есть в Java или C# настолько крутая реализация ОО парадигмы, что в этих языках в принципе нельзя ошибиться в архитектуре? В любом языке можно "выстрелить себе в ногу".
            Ответить
            • В Java можно написать бесконечное число ненужных вербозных классов которые ничего не делают не имеют внятных инвариантов и просто засирают вам ssd (hdd в вашем случае)
              Ответить
      • Хуексины.
        Ответить
    • public ALTERNATIVEK::cstore_this<GAMEPLAYER::cC ar>
      Реально рульный предок.
      Ответить
      • Ну вот только из-за этого предка это и говнокод, так сказать.
        Ответить
        • А для чего сдесь этот предок и что он делает?
          Ответить
          • Этот предок в своём конструкторе пихает this в контейнер, объявленный как статический член, и удаляет this из этого контейнера в деструкторе.
            Ответить
            • одной строкой класс наделили способностью хранить свой экземпляр в каком либо списке... что может быть удобнее...
              Ответить
              • С этим я пожалуй соглашусь. :-) Буду юзать для данного действа. )))
                Ответить
              • Тоже самое делается заведением поля спец. класса, который получает в конструктор указатель и кладёт его в контейнер. В деструкторе чистит контейнер. По объёму кода то же самое - одна строчка в объявлении класса.
                Ответить
                • Да но для доступа к спецклассу необходимы дополнительные врапперы...
                  Ответить
    • а я бы не взялся судить только по этому куску. Любопытно что умеют эти классы и что именно происходит :)
      Ответить
    • >...
      { //... дальше не интересно
      Интересно, а что там дальше? :)
      Ответить
    • Си Плюс Плюс!

      Есть много языков,
      Но С++ таков:
      Кто в С++ попал --
      Навеки счастлив стал!

      Си Плюс Плюс!

      Поверьте, люди лгут,
      Что С++ не крут.
      И как волшебный сон,
      Так вдохновил нас он!

      Си Плюс Плюс!
      Ответить
      • Опладирую сидя!.. сидя в кресле перед компом. Очнь понровилась! Афтар пиши исчо. Ажидаем тваих тварений. Я серьёзно. :)
        Ответить
    • Ахах! Фрахаю хаХАХАхеХаааа... Хаааа!!! АААААААААХАХААААААА! Хаххахххаааа.
      Ответить
    • блядь гугл что ты делаеш
      https://i.postimg.cc/D0QT4jyP/image.png
      Ответить

    Добавить комментарий