Подскажите по наследованию...

Тема в разделе "LANGS.C", создана пользователем Green_DiCk, 4 дек 2008.

  1. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А предпринимается вот что, в контейнере создаётся новый экземпляр класса Parent, и вызывается конструктор копирования тоже класса Parent. :) То есть Child-а там не будет и в помине. По-этому я и рекомендую передавать указатель или ссылку.
     
  2. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    217.118.66.101

    Booster
    ммм... спасибо. че то я действительно как-то того.. сам не допер..

    а по вирт. методам вопрос еще -
    если метод определен как виртуальный и делаем так:

    Код (Text):
    1. class Parent {public virtual void foo() {// do something}};
    2. class Child : public Parent {public virtual void foo() {// do something different}};
    3.  
    4. Parent * GetObject() {// некая ф-ция, возвращающая указатель либо на Parent либо на Child }
    5.  
    6. void main()
    7. {
    8.     GetObject()->foo();  // что будет если GetObject вернет дочерний экземпляр?
    9. }
    Механизм вирт. ф-ций сам разберется с каким экземпляром имеет дело? Или надо явно приводить указатель к тому типу, который нужен?
     
  3. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Green_DiCk
    Вызов виртуальных функций происходит через таблицу, а она формируется в момент создания экземпляра класса, в период исполнения. Так что в этом случае ничего приводить не надо, для этого виртуальные функции и вводились.
     
  4. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Сложно, однако, вы решаете простую задачу. Отсюда, имхо, и проблемы все. Хорошо-бы сперва все нарисовать на бумажке. Определить минимально необходимое колво интерфейсов (публик фунок в классе). Назвать их по типу операции не привязываясь к типу элемента(?). Разбить на общие, более общие и совсем частные операции/свойства. Нарисовать квадратиками и стрелочками иерархию наследования, на какомто уровне определить обработчики возможно неиспользуемых/непереопределяемых интерфейсов (например у базик класса). А потом уже чтото писать. Глядишь и стл с кастингом совсем не понадобятся. Те абсолютно. И еще. Имхо hwnd или hdc или буфер под битмап разумнее передавать в рендерер напрямки, а не задавать при создании класса.

    Стандартная отмазка: "Все написанное выше - только мое имхо. Иметь же вами своего имхо запретить пока не получается".
     
  5. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    217.118.66.101

    _basmp_
    >Хорошо-бы сперва все нарисовать на бумажке.

    Нарисовал. Показалось что ВСЁ нарисовал. Начал писать - полезли огрехи в проектировании. Недостаток опыта в ООП не позволяет все точно изложить на бумажке. так что приходится применять итерационный подход - рисование на бумажке перемежать с кодингом, на каждой итерации совершенствуя и архитектуру и ее реализацию.

    >Имхо hwnd или hdc или буфер под битмап разумнее передавать в рендерер напрямки, а не задавать при создании класса.

    ничо не понял. но как мне кажется у меня неплохо сделано - в каждый экземпляр спрайта передается указатель на HDC. и каждый спрайт выводит себя сам на этот HDC. HDC находится в классе движка и инициализируется там же.

    PS еще одна проблемка тут нарисовалась. не по теме правда, но по-моему достаточно пустяковая - новый тред заводить неохота. Вообщем надо сообщения от мыши ловить. Завел в движке отдельный поток, который в цикле делает PeekMessage(&msg, pEngine->hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE | PM_QS_INPUT)
    Не работает. почитал про PeekMessage в MSDN:
    "...
    hWnd
    [in] Handle to the window whose messages are to be examined. The window must belong to the current thread...."
    Как быть?
     
  6. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А зачем тебе отдельный поток?
     
  7. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    217.118.66.101

    >А зачем тебе отдельный поток?

    Птмшт движок должен быть не привязан к конкретной библиотеке. Сейчас я его например тестирую в диалоговом MFC приложении. Но он должен также легко внедряться в какой-нибудь Borland VCL и т.д.

    если писать "голое" Windows-приложение, то там можно определить процедуру обработки оконных сообщений и в ней отлавливать мышиные и передавать движку. А если у меня MFC? Здесь же уже все скрыто под MFC каркасом. Можно конечно добавить в класс диалога обработчики мышиных сообщений и из обработчиков передавать сообщения в движок. Но это уже менее универсально, т.к. в VCL придется делать еще как то иначе и т.д.

    так как сообщения посылаются окну, то было бы замечательно просто получить хэндл окна, передать его в движок и не заморачиваться с особенностями конкртных платформ. ну а чтобы движок мог помимо обработки сообщений делать и другие дела нужен отдельный поток.
     
  8. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А для чего там сообщения? Может лучше без них.
     
  9. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    217.118.66.101

    >А для чего там сообщения? Может лучше без них.

    А как без них?? DirectInput? Или еще чего?
    а то погуглил немного - действительно у чужого окна не так то просто сообщения получать. Только хаки-хуки всякие...
     
  10. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Я имею ввиду, что может можно продумать интерфейс иначе.
    По-моему сообщения или ввод лучше сделать снаружи библиотеки.
     
  11. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    217.118.66.101

    Теперь по конструкторам вопрос. Начал дочерние спрайты тестировать и сразу траблемы полезли. Суть такова:

    Код (Text):
    1. class Parent
    2. {  
    3.     int member;
    4.     public:
    5.     Parent(){}     // мне этот конструктор не нужон. но без него не компилируется
    6.     Parent(int a){member = a;}
    7. };
    8.  
    9. class Child : public Parent
    10. {
    11.      public:
    12.      Child(int a){Parent::Parent(a);}
    13. };
    14.  
    15.  
    16. void main()
    17. {
    18.     Child * child_object = new Child(10); // но это не прокатывает.
    19.     //поле member почему-то остается непроинициализированным
    20. }
    после всех вызовов member становится == 0xcdcdcdcd
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Код (Text):
    1. class Parent
    2. {  
    3. public:
    4.     Parent(){}     // мне этот конструктор не нужон. но без него не компилируется
    5.     Parent(int a):member(a)
    6.    {}
    7. protected:
    8.    int member;
    9. };
    10.  
    11. class Child : public Parent
    12. {
    13. public:
    14.      Child(int a):Parent(a)
    15.      {}
    16. };
    17.  
    18.  
    19. void main()
    20. {
    21.     Child * child_object = new Child(10);
    22. }
     
  13. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    Booster
    Ага. Работает. Спасибо. Только почему не работает мой вариант я так и не вкурил.
     
  14. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    Green_DiCk
    потому что у тебя в классе Parent всё было размещено в private-секции данных, и конструктор(ы) в том числе и из наследника ты никак не сможешь "достучаться" до конструктора его parent-а, который private.
    (равно как и создать инстанцию класса Parent вообще).
     
  15. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Это интересный вопрос. Конструкторы это статические функции, для их вызова не нужен сам объект.
    {Parent::Parent(a);} - это просто вызов некой функции и не более.
    this->Parent::Parent(a); - вот это вызов конструктора для текущего объекта.

    Вначале вызываются конструкторы базовых классов, а уже потом наследуемых.

    Child(int a){Parent::Parent(a);}
    Вначале вызовется конструктор Parent(), затем Child(int a), а затем функция Parent(a).

    Child(int a):Parent(a){}
    Вначале вызывается конструктор Parent(int a), затем Child(int a), что нам и надо.

    protected для member можно поменять на private это сути не меняет.

    Кстати если вызвать из Child любой другой метод, например Parent::foo(), то всё будет нормально, но не для конструктора.
     
  16. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    217.118.66.101

    varnie
    >потому что у тебя в классе Parent всё было размещено в private-секции данных, и конструктор(ы) в том числе

    Ложь. Конструкторы у меня публичные. См. внимательнее.

    Booster
    >{Parent::Parent(a);} - это просто вызов некой функции и не более.

    Во те раз.. А какой такой member тогда проинициализируется, если это просто статическая ф-ция и нет никакой инстанции (как говорит varnie)?
     
  17. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    Green_DiCk
    !!! я только счас увидел что у тебя там объявлена public. :dntknw:(( извиняюсь!
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Создаётся временный объект и для него вызывается конструктор. Конструктор для объекта вызывается только один раз, если только не вызвать его через объект.
    Извиняюсь, конечно конструкторы не статические. ;)

    Да, интересный это оказался вопрос.
    Код (Text):
    1. class Child
    2. {
    3. public:
    4.   Child()
    5.   {}
    6.    Child(int a)
    7.    {
    8.        Child(a); - ошибка - redefinition of formal parameter a.
    9.    }
    10. };
    Непонято откуда взялась эта ошибка, причём если заменить Child(a); на Child::Child(a); то всё ок, причём поведение в этих случаях не меняется, происходит всё тот же рекурсивный вызов с временным объектом.

    Что-то странное здесь твориться, проверялось на VS 2003 и VS 2005.
     
  19. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Green_DiCk
    Очень благодатный получился у тебя вопрос.
    Что касается повторных вызовов конструкторов, то как минимум это плохо. А как максимум пресекается компилятором. Например оказалось, что Comeau не даёт делать подобные этому вызовы Obj.T::T(); Проверьте сами - http://www.comeaucomputing.com/tryitout/ Возможны только вызовы типа - T(); Которые создают временный объект.

    Дальше оказалось ещё веселее. Как вам такое?

    Код (Text):
    1. class T
    2. {
    3. public:
    4.   int p;
    5. };
    6.  
    7. int main()
    8. {
    9.     T(qwerty);
    10.     qwerty.p = 5;
    11. }
    Поддерживается и студией и Cameau. Это для меня оказалось новинкой.