Зацикливание классов., David, 29-Мрт-02, 13:03 [смотреть все]Заранее извиняюсь, если вопрос покажется слишком ламерским. Есть два класса, зацикленных друг на друге и объявленных в разных файлах: <<<x.h>>> #include "y.h" class y; class x { public: x(): yobj(*this) {} private: y yobj; }; <<<y.h>>> #include "x.h" class x; class y { public: y(x& xx): xobj(&xx) {} private: x* xobj; }; На это дело компилер выдаёт такую ругань: In file included from y.h:5, from y.cpp:2: x.h:18: field `yobj' has incomplete type. Объясните, пожалуйста, что ему, собственно, надо. Я предполагаю, что, скорее всего от этого можно избавиться, если впихнуть объявления классов в один файл, но дело в том, что реально классов гораздо больше и они гораздо сложнее, чем в этом примере, и этого очень желательно избежать. Заранее спасибо. Только не сильно ругайтесь :).
|
- RE: Зацикливание классов., Арлекин, 13:31 , 29-Мрт-02 (1)
ТАК "лучше не делать". Ты пытаешься использовать С++ как С. Увы, но это разные языки, хоть и вырос первый из второго. В лучшем случае ты просто запутаешься - при правильной иерархии классов два класса не могут одновременно быть и родителем и дитем между собой (в плюсах есть понятие "Множественное наследование"- когда классы могут быть родителями или/и детьми). Дети видят и могут юзать на прямую всё что у папы protected ( ну и public ессно ). Есть достаточно мощный механизм виртуальных функций - когда каждый ребенок может переопределить ее (функции) сигнатуру. ИМХО, твои проблемы в неправильной идеологии классов проекта. Самое простое - купить БИБЛИЮ ( 3-е издание "Страуса", на русском уже есть, стоит ~500 р. ) и почитать. Туго по-началу, но потом легко будет. Ну и переделывать придется.
- Здесь наследования и близко нет., David, 20:58 , 29-Мрт-02 (2)
>два класса не могут >одновременно быть и родителем и >дитем между собой Так причём тут наследование? Классы x и y не состоят ни в каких родственных связях. Они просто юзают друг друга. Это достаточно типичный случай, например, когда список содержит элементы определённого класса и каждый элемент содержит ссылку на список, к которому принадлежит. В моём конкретном случае класс x является как бы глобальным центральным управляющим узлом, в котором содержатся объекты (y), выполняющие конкретные функции. Для того, чтобы этим объектам взаимодействовать друг с другом, я им передаю ссылку на x, чтобы метод объекта класса y мог обратиться к объекту x.z таким образом: xobj->z >Самое простое - >купить БИБЛИЮ ( 3-е издание >"Страуса", на русском уже есть, >стоит ~500 р. ) и >почитать. Туго по-началу, но потом >легко будет. Ну и переделывать >придется. А это не спорю. Как только деньги появятся, обязательно куплю, хотя C++ в теории я знаю неплохо. Проблема с практикой.
- RE: Здесь наследования и близко нет., XMan, 22:22 , 29-Мрт-02 (3)
Короче, он тебе говорит, что ты пытаешься пользовать класс, который уже есть, но еще не полностью определен. И он прав. Смотрим сами:Определяется класс A, в котором (непосредственно в определении) имеется ссылка на класс B. Нет проблем - идем для начала определять класс B. Находим и видим, что в нем (тоже в определении) имеется ссылка на класс A, который еще не определен (он только в процессе). Что мы будем делать ? Первый вариант - идти определять класс A. И так в цикле, пока памяти на машине хватит, а потом свалимся. Компилер пошел по второму пути :)) Я вижу 2 выхода: 1. Раскидать классы по другому; 2. Вынести вызовы соседа из определения класса (*.h) в код конструктора/метода класса (*.cpp) и потом просто в каждом файле *.cpp вставить соответствующие #include PS. Или я чего-то не понимаю ?
- RE:Хочу добавить., Арлекин, 11:20 , 30-Мрт-02 (4)
Во-первых: Если классы взаимодействуют между собой так, что им нужна только часть функциональности друг друга, обычно делается базовый класс ( или они оба будут предками - не принципиально )исключительно для работы с общей областью. Например есть классы ШКАФ и СТОЛ. Кроме того что они могут быть оба деревянными, их оба можно собирать используя ключ на 12. В таком случае "сборщик мебели" должен быть отдельным классом, и крутить гайки где угодно - и в ШКАФ и в СТОЛ. И все гайки и ключ должны быть у сборщика, а не перетаскиваться из ШКАФ в СТОЛ и назад. А если классы отличаются только типом данных - прямая дорога в шаблоны, хотя я ниразу не построил модель данных в них нуждающуюся. Во-вторых: Я плохо понимаю что такое "знать ЯП в теории". Но не суть - дело не в том, что в твоей задаче нет наследования, а в том, что ты НЕПРАВИЛЬНО организовал структуру классов и с точки зрения идеологии и с точки зрения подхода. Например - по возможности ВСЕГДА НАДО выносить тела функций ( ну кроме inline и совсем уж маленьких ) в файл .[cc,cpp]. В-третьих: Наследование как папа/дите вещь совершенно не обязательная - сделай базовый класс Tools который будет иметь ТОЛЬКО функции сборки мебели. Тоже наследование, своеобразное правда. Именно в этом случае (ты писАл, что работал в винде) показательно было бы разобрать структуру классов какого-нибудь MFC-приложения в MSVC ( для других целей он плохо подходит ).ЗЫЖ Когда я начинал юзать плюса я налетал на теже грабли - через это все проходят. Дело не в том, что кто-то не умеет "мыслить на уровне объектов", а в том, что ПРИМЕНИТЬ это умение к С++ можно только после приличной практики. Это как пользоваться const вместо #define - "сначала боишься, потом гордишься" :-)
- RE: Здесь наследования и близко нет., Арлекин, 11:33 , 30-Мрт-02 (5)
... В моём конкретном случае класс x является как бы глобальным центральным управляющим узлом, в котором содержатся объекты (y), выполняющие конкретные функции. Для того, чтобы этим объектам взаимодействовать друг с другом, я им передаю ссылку на x, чтобы метод объекта класса y мог обратиться к объекту x.z таким образом: xobj->z ... Ага - "нет наследования". Твои Y derived от virtual Х и тогда все protected члены Х доступны НАПРЯМУЮ в любом Y от одного Х, инициализированного последним Y. #include "class_x.h" class Y: virtual {public|private|protected} X { ... } Это если кол-во Y известно заранее и инициализируется одновременно. Если это все происходит динамически - Х не виртуальный, но каждый Х есть derived от абстрактного класса Z.
- Всё заработало, David, 15:18 , 30-Мрт-02 (6)
Всё заработало когда я заменил экземпляр yobj на ссылку *yobj и инициализировал её в конструкторе с помощью new. Видимо для ссылок подходит и неполное определение класса. Так что большое спасибо за попощь. 2 Арлекин: Я тоже сторонник ГРАМОТНОГО программирования, и мне приятно общаться с человеком, который думает так же. Не хочется спорить по поводу того, нужно тут делать наследование или нет, потому что мы находимся в неравных условиях, т.к. я знаю задачу, а ты нет. В общем - спасибо.
|