А предпринимается вот что, в контейнере создаётся новый экземпляр класса Parent, и вызывается конструктор копирования тоже класса Parent. То есть Child-а там не будет и в помине. По-этому я и рекомендую передавать указатель или ссылку.
217.118.66.101 Booster ммм... спасибо. че то я действительно как-то того.. сам не допер.. а по вирт. методам вопрос еще - если метод определен как виртуальный и делаем так: Код (Text): class Parent {public virtual void foo() {// do something}}; class Child : public Parent {public virtual void foo() {// do something different}}; Parent * GetObject() {// некая ф-ция, возвращающая указатель либо на Parent либо на Child } void main() { GetObject()->foo(); // что будет если GetObject вернет дочерний экземпляр? } Механизм вирт. ф-ций сам разберется с каким экземпляром имеет дело? Или надо явно приводить указатель к тому типу, который нужен?
Green_DiCk Вызов виртуальных функций происходит через таблицу, а она формируется в момент создания экземпляра класса, в период исполнения. Так что в этом случае ничего приводить не надо, для этого виртуальные функции и вводились.
Сложно, однако, вы решаете простую задачу. Отсюда, имхо, и проблемы все. Хорошо-бы сперва все нарисовать на бумажке. Определить минимально необходимое колво интерфейсов (публик фунок в классе). Назвать их по типу операции не привязываясь к типу элемента(?). Разбить на общие, более общие и совсем частные операции/свойства. Нарисовать квадратиками и стрелочками иерархию наследования, на какомто уровне определить обработчики возможно неиспользуемых/непереопределяемых интерфейсов (например у базик класса). А потом уже чтото писать. Глядишь и стл с кастингом совсем не понадобятся. Те абсолютно. И еще. Имхо hwnd или hdc или буфер под битмап разумнее передавать в рендерер напрямки, а не задавать при создании класса. Стандартная отмазка: "Все написанное выше - только мое имхо. Иметь же вами своего имхо запретить пока не получается".
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...." Как быть?
217.118.66.101 >А зачем тебе отдельный поток? Птмшт движок должен быть не привязан к конкретной библиотеке. Сейчас я его например тестирую в диалоговом MFC приложении. Но он должен также легко внедряться в какой-нибудь Borland VCL и т.д. если писать "голое" Windows-приложение, то там можно определить процедуру обработки оконных сообщений и в ней отлавливать мышиные и передавать движку. А если у меня MFC? Здесь же уже все скрыто под MFC каркасом. Можно конечно добавить в класс диалога обработчики мышиных сообщений и из обработчиков передавать сообщения в движок. Но это уже менее универсально, т.к. в VCL придется делать еще как то иначе и т.д. так как сообщения посылаются окну, то было бы замечательно просто получить хэндл окна, передать его в движок и не заморачиваться с особенностями конкртных платформ. ну а чтобы движок мог помимо обработки сообщений делать и другие дела нужен отдельный поток.
217.118.66.101 >А для чего там сообщения? Может лучше без них. А как без них?? DirectInput? Или еще чего? а то погуглил немного - действительно у чужого окна не так то просто сообщения получать. Только хаки-хуки всякие...
Я имею ввиду, что может можно продумать интерфейс иначе. По-моему сообщения или ввод лучше сделать снаружи библиотеки.
217.118.66.101 Теперь по конструкторам вопрос. Начал дочерние спрайты тестировать и сразу траблемы полезли. Суть такова: Код (Text): class Parent { int member; public: Parent(){} // мне этот конструктор не нужон. но без него не компилируется Parent(int a){member = a;} }; class Child : public Parent { public: Child(int a){Parent::Parent(a);} }; void main() { Child * child_object = new Child(10); // но это не прокатывает. //поле member почему-то остается непроинициализированным } после всех вызовов member становится == 0xcdcdcdcd
Код (Text): class Parent { public: Parent(){} // мне этот конструктор не нужон. но без него не компилируется Parent(int a):member(a) {} protected: int member; }; class Child : public Parent { public: Child(int a):Parent(a) {} }; void main() { Child * child_object = new Child(10); }
Green_DiCk потому что у тебя в классе Parent всё было размещено в private-секции данных, и конструктор(ы) в том числе и из наследника ты никак не сможешь "достучаться" до конструктора его parent-а, который private. (равно как и создать инстанцию класса Parent вообще).
Это интересный вопрос. Конструкторы это статические функции, для их вызова не нужен сам объект. {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(), то всё будет нормально, но не для конструктора.
217.118.66.101 varnie >потому что у тебя в классе Parent всё было размещено в private-секции данных, и конструктор(ы) в том числе Ложь. Конструкторы у меня публичные. См. внимательнее. Booster >{Parent::Parent(a);} - это просто вызов некой функции и не более. Во те раз.. А какой такой member тогда проинициализируется, если это просто статическая ф-ция и нет никакой инстанции (как говорит varnie)?
Создаётся временный объект и для него вызывается конструктор. Конструктор для объекта вызывается только один раз, если только не вызвать его через объект. Извиняюсь, конечно конструкторы не статические. Да, интересный это оказался вопрос. Код (Text): class Child { public: Child() {} Child(int a) { Child(a); - ошибка - redefinition of formal parameter a. } }; Непонято откуда взялась эта ошибка, причём если заменить Child(a); на Child::Child(a); то всё ок, причём поведение в этих случаях не меняется, происходит всё тот же рекурсивный вызов с временным объектом. Что-то странное здесь твориться, проверялось на VS 2003 и VS 2005.
Green_DiCk Очень благодатный получился у тебя вопрос. Что касается повторных вызовов конструкторов, то как минимум это плохо. А как максимум пресекается компилятором. Например оказалось, что Comeau не даёт делать подобные этому вызовы Obj.T::T(); Проверьте сами - http://www.comeaucomputing.com/tryitout/ Возможны только вызовы типа - T(); Которые создают временный объект. Дальше оказалось ещё веселее. Как вам такое? Код (Text): class T { public: int p; }; int main() { T(qwerty); qwerty.p = 5; } Поддерживается и студией и Cameau. Это для меня оказалось новинкой.