- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 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>
{ //... дальше не интересно
Попробуйте и вам понравится...
Автору кода респект...
Респект - рили!?
но с тех пор я действительно многое понял. когда миксины пишешь сам это хорошо и здорово, а когда приходится отлаживать их за кем-то, то это уже не так весело.
в любом случае это не отменяет респекта автору.
спсибо!!!
http://blog.gamedeff.com/?p=91
class A: private T1, private T2 {
<here comes the code>
};
Такого потрясающего способа создавать полифункциональные классы ни в Java нету.
Хотя код выше я признаю эксцентричным, но можно предположить, что это множественное наследование нужно для того, чтобы в разные маленькие функции-нечлены подсовывать "кусочки" интерфейса, которые представляют интерфейс-контракт именно с данной функцией.
Такого потрясающего способа задания полифункциональных классов и не надо. Ни в C++, ни в C#, ни в 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>
{
};
никаких виртуальных вызовов слушателей делегатов и тп, все ошибки на этапе компиляции, одна проблема один класс - это все о чем пишут самые лучшие проектировщики...
самые лучшие проектировщики пишут, что нужно именно так делать?
Есть большой недостаток, это сильно растет время компиляции так как сложно что-то вынести в cpp файлы (хотя можно макрос THIS переписать немного по-другому и писать конкретные специализации шаблона, но это убьет все преимужества)
в общем это метод для тех кто не любит копипаст и функции типа
void SomeMethod()
{
m_obj->SomeMethod();
}
Это только твое личное мнение. Наследование реализации вместе с интерфейсом - это очень удобный механизм, которого иногда очень не хватает в 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 (похожие классы лучше делать почти одинаковым набором миксин)...
Мне кажется такой код сложно ваять большой толпой, но я не пробовал, может быть и нетрудно.
По поводу отладки, я бы не сказал что тут будет сложно. Потому что при выполнии уже утвердились все инстансы шаблонов, так что для отладки есть информация.
В ANSI C это делается за пару секунд и поддерживается проще некуда. А тут мозгошлёбства на три вагона ни для чего.
Реально рульный предок.
{ //... дальше не интересно
Интересно, а что там дальше? :)
Есть много языков,
Но С++ таков:
Кто в С++ попал --
Навеки счастлив стал!
Си Плюс Плюс!
Поверьте, люди лгут,
Что С++ не крут.
И как волшебный сон,
Так вдохновил нас он!
Си Плюс Плюс!
https://i.postimg.cc/D0QT4jyP/image.png