абстрагирование от платформы - виртуальный функции

Тема в разделе "LANGS.C", создана пользователем maksim_, 21 янв 2010.

  1. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    сейчас занимаюсь проектом под арм. возникла идейка - абстрагировать код от конкретного камня. создаём структуру папок, что-то типа:

    +-src
    +-system
    +-my_src

    в system всё платформенно зависисое. на верхнем уровне убстрагируем, н-р CTimer, CAdc и пр. т.е. сама прога обращается исключительно к абстрактным классам, реализация которых создаётся своя под конкретный проц (соответственно, меняем файлики в папке system). вопрос такой. стоит ли создавать базовые классы абстрактными? это ведь повлечёт за собой генерацию таблицы виртуальных функций, что по идее нафиг здесь не нужно - тут нет никакого виртуального полиморфизма. т.е.


    system.h:
    Код (Text):
    1. class CTimer
    2. {
    3. public:
    4.   virtual void do_run() = 0;
    5.   virtual void do_stop() = 0;
    6.  ...
    7. };
    ну и реализация для конкретного камня:
    \system\timer.h
    Код (Text):
    1. class CTimerImpl :
    2.   public CTimer
    3. {
    4. public:
    5.   virtual void do_run() { ... }
    6.   virtual void do_stop() { ... }
    7. };
    вобщем вопрос: нужно как-то абстрагироваться от конкретных реализаций CTimerImpl и юзать в проге только CTimer. при этом хотелось бы обойтись без vftable. какие есть соображения?
     
  2. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Если я правильно понял вопрос, то есть такая штука, как статический полиморфизм: ты определяешь шаблонный класс, от которого потом наследуешься, параметризуя его собой:
    Код (Text):
    1. template<class T>
    2. class CTimerImpl
    3. {
    4.        //тут например есть функция seconds
    5.        //ее код не зависит от платформы
    6. public:
    7.       unsigned long seconds()
    8.       {
    9.               return ((T*)this)->ticks() / ((T*)this)->ticks_per_second();
    10.       }
    11.       //и т.д.
    12. }
    13. //а реализация конкретного таймера для конкретной платформы такая:
    14. class CTimer: public CtimerImpl<CTimer>
    15. {
    16.      friend CtimerImpl<CTimer>;
    17.      unsigned long ticks(){...}
    18.      unsigned long ticks_per_second() const {...}
    19. }
     
  3. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    Velheart что-то не совсем врубился. надо подумать...
    в моём примере Impl от слова Implementation - реализация для конкретной платформы. у тебя они наоборот.
     
  4. reversecode

    reversecode Guest

    Публикаций:
    0
    class CTimer: public CtimerImpl<CTimerWin32>
    class CTimer: public CtimerImpl<CTimerARM>

    итд
    будет выглядеть лучше
    но

    это решает проектировщик
     
  5. Noga

    Noga New Member

    Публикаций:
    0
    Регистрация:
    10 окт 2008
    Сообщения:
    92
    maksim_

    Чтобы понять статический полиморфизм, можно посмотреть ATL. Там аналогичная схема.
     
  6. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    капец какие сложности. обычно, делают так, отделяют общие хидеры и делают под них общие и кучу поплатформенных реализаций. а в мэйкфайле(-лах) пишут как собирать для данной платформы

    например:
    include/ # общие хидеры

    # поплатформенные реализации/хидеры
    386-nt/
    386-lin/
    arm-ce/
    arm-lin/
    ppc-lin/

    # общие реализации
    common/

    а во внешнем мэйкфайле чтонибудь вроде

    PLAT=386-nt # 386-nt 386-lin arm-ce arm-lin ppc-lin

    all:
    cd $(PLAT)
    make

    или

    OBJ=\
    $(PLAT)\file1.$(O)\
    $(PLAT)\file2.$(O)\
    ...
    $(PLAT)\fileN.$(O)\
    common\fileN1.$(O)\
    common\fileN2.$(O)\
    ...
    common\fileNM.$(O)\

    все зависит от задачи

    хотя можно и гораздо сложнее. опять же определяется собственной задачей автора.
     
  7. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
  8. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Ну нет, pImpl овехед и не для этого. Компайл-тайм полиморфизм делается через CRTP, как пишет Velheart, на худой конец traits, или перегрузкой =)
     
  9. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    J0E

    Один лишний call - офигеть какой оверхед, да и то спорно, что он вообще будет (при link-time кодогенерации скорее всего никакого оверхеда не будет). А что значит "не для этого"? Pimpl как раз нужен для абстрагирования от платформы и поддержания чистоты заголовочных файлов с платформно-независимым интерфейсом.

    CRTP тут вообще не в кассу. В данном случае он бессмыслен без дополнительного динамического полиморфизма, т.к. пользовательские классы не будут иметь платформно-независимого интерфейса -наружу будет торчать платформно-зависимый шаблонный параметр, а следовательно задача ТС не решена.
     
  10. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    _DEN_
    +1
     
  11. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    я не совсем понимаю - зачем вообще юзать шаблоны. не будет же апликуха одновременно работать на десяти платформах. вобщем в чём суть. есть класс CTimer - абстракнтый, только интерфейс к которому обращается прога. реализация этого класса своя для каждой конкретной платформы - CTimerImpl. реализация под каждую платформу в отдельном файлике, н-р: timer_x86.h timer_x86.cpp, timer_sam7.h timer_sam7.cpp. в зависимости от того, под какую платформу в данный момент идёт сборка - те файлики и подключаем к проекту. вопрос только в том, что базовые методы у всех классов CTimerImpl должны быть одинаковыми - для этого и нужен абстрактный CTimer. проблема: если делать CTimer абстрактным, с виртуальными методами - будет сгенерирована vtable, которая тут нафиг не нужна.
     
  12. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    я подумал - абстрактный вообще не нужно создавать. даже если класс абстрактный - всё равно в момент создания объекта нужно писать CTimer *p_timer = new CTimerImpl. то есть опять делаем код программы платформенно зависимым. пока что такой вариант:

    timer_x86.h:
    Код (Text):
    1. #if CURRENT_PLATFORM = _X86_
    2. class CTimer
    3. {
    4.  // implementation for x86
    5. };
    6. #endif
    timer_sam7.h:
    Код (Text):
    1. #if CURRENT_PLATFORM = _SAM7_
    2. class CTimer
    3. {
    4.  // implementation for sam7
    5. };
    6. #endif
    и т.д. работать будет но плохо что CTimer не стандартизирован на верхнем уровне. не понятно какие методы являются внешними и обязательны для реализации. с интерфейсом было бы всё понятнее.
     
  13. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Шаблоны нужны что бы явно определить интерфейс и уйти от виртуальных функций. http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism

    Код (Text):
    1. template<class TimerImplementation>
    2. struct TimerInterafce
    3. {
    4.   typedef TimerImplementation Implementation;
    5.   void run() { static_cast<Implementation*>(this)->do_run(); }
    6.   void stop() { static_cast<Implementation*>(this)->do_stop(); }
    7. };
    8.  
    9. struct TimerImplSome : TimerInterafce<TimerImplSome>
    10. {
    11.   void do_run() { ... }
    12.   void do_stop() { ... }
    13. };
    конечно можно и без них в С стайле, как в #6

    Вызов new спорно? :) так надо ити не по первой попавшийся ссылке в гугле, которая на твой сайт, а читать Саттера http://gotw.ca/gotw/028.htm
    Если бы написал "для уменьшения зависимостей" я бы не спорил, возможно pimpl в конечном счете тож пригодится.
     
  14. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    J0E

    Вызов new будет происходить один раз на создение одного объекта. У тебя будет создаваться стопитсот объектов каждую секунду? Это вряд ли.

    Ооо, спасибо, Кэп, а кто такой Саттер?

    Основной смысл, почему CRTP тут не в тему в том, что для каждой платформы шаблон будет использоваться с одним и тем же единственным шаблонным параметром, что делает его использование совершенно бессмысленным. С таким же успехом можно просто написать N классов и инклудить нужный в зависимости от платформы. В данном случае CRTP в качестве надсмотрщика за интерфейсом выглядит слишком неестественным - требования к интерфейсу платформно-зависимого класса будут размазаны по внутренним дактайповым вызовам функций класса-реализации в платформно-независимом классе. Здесь бы гораздо лучше подошли концепны, которых в С++ пока что нет.

    Pimpl в данной задаче имеет все преимущества. Во-первых - строго определяет платформно-независимый интерфейс, через который должны работать реализации. Во-вторых - не выпускает платформно-зависимые определения наружу, не давая юзеру возможности на них завязаться (что, к тому же, значительно ускоряет компиляцию). Один new за это все - слишком большая плата? Ну извините, тогда лучше вообще оставить С++ и программировать на ассемблере.

    Не знаю как там в ваших википедиях, а в реальной жизни CRTP обычно применяется в паре с динамическим полиморфизмом :)
     
  15. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    *концепты
     
  16. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    откуда я знаю что у автора? таймер довольно мелкий объект и наверняка не один.
    Не позорьтесь прилюдно, батенька. He served for over a decade as secretary and chair of the ISO C++ standards committee during the development of the second C++ standard, C++0x, and as lead architect of C++/CLI at Microsoft
    Смотри #4
    Я расшифровал твои слова "Один лишний call", забыв про delete. Ты забыл еще про постоянное разыменовывание указателя.

    pimpl - почти vtbl сделанная руками. понимаю, когда оно юзается для exception safety, для транзакционности. В данном случе тогда проще оставить абстрактный класс, чем программировать на ассмеблере в С++.
     
  17. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    J0E

    Омг, да я, оказывается, тролль-адепт :) Кто такой Саттер я узнал лет шесть назад.

    #4 никак не отвечает на мой вопрос :)

    "постоянное разыменовывание указателя" - это и есть один лишний call. Если мы опустились до деталей реализации, то вызов функции по указателю - это обычный вызов функции с неявной передачей this. И опять же, при link-time кодогенерации это все скорее всего будет упразднено. Что же касается создания и удаления объектов... Если платформно-зависимые сущности создаются и удаляются по миллиону раз в секунду, то проблемы будут как с pimpl, так и с CRTP, и связаны они будут далеко не с абстрактной оберткой.

    Нет. pimpl полностью известен в compile-time и оптимизатору справиться с ним гораздо легче. С vtbl это будет гораздо сложнее, а в большинстве случаев вызов виртуального метода вообще не будет поддаваться оптимизации.
     
  18. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Бгг, это команда
    mov reg, [this+disp32]
    Короче, ты можешь авторитетно фантазировать что угодно, но было бы неплохо разобраться перед этим самому ;)
     
  19. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    J0E

    Лолшто? В pimpl разыменовение указателя используется ТОЛЬКО для вызова мембер функций, еслечо.

    Начни с себя :derisive:
     
  20. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    _DEN_ при чём вообще сколько объектов будет создаваться - олин или пятьсот? ты уходишь от сути: локализовать платформенно зависимый код. какого лешего посреди программы будет торчать какой-нибудь CTimer *p = new CTimerImpl<CTimerWin32>; ? всё обрамлять ифдефами?

    сколько я ни читал все те ссылки, которые здесь были представлены - я так и не понял как CRTP или PIMPL помогут локализовать платформенно зависимый код. наверное, я дурак и до меня не доходит, но ведь шаблонный параметр будет отовсюду торчать. в любом случае код придтся обрамлять #if'ами.