The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Зацикливание классов., !*! 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 Арлекин: Я тоже сторонник ГРАМОТНОГО программирования, и мне приятно общаться с человеком, который думает так же. Не хочется спорить по поводу того, нужно тут делать наследование или нет, потому что мы находимся в неравных условиях, т.к. я знаю задачу, а ты нет. В общем - спасибо.



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру