Наследование и несколько файлов в C ++ - PullRequest
2 голосов
/ 06 августа 2011

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

Мой класс - это класс сокетов, а производными классами являются socket_udp, socket_tcp, socket_raw и т. д.

Как решить круговую зависимость?Может быть, дизайн класса плох, и мне не нужны разные классы для разных типов сокетов?Я немного запутался здесь.

Спасибо!

Ответы [ 4 ]

8 голосов
/ 06 августа 2011

Одним из вариантов будет создание нового файла заголовка, который включает все файлы заголовков для производных и базовых объектов. Следовательно, включение только одного заголовка включало бы все остальные файлы заголовков. Если вы упорядочите включения в этом файле, чтобы никогда не включать класс без предварительного включения всех его родительских классов, вы можете избежать циклических зависимостей.

3 голосов
/ 06 августа 2011

Можно добавить директивы #include к основанию заголовка базового класса, чтобы принудительно включить производные классы после определения базового класса.

Тогда заголовки производного класса не будут нуждаться в #include заголовке базового класса, прерывая цикл.

2 голосов
/ 06 августа 2011

Если определение базового класса по какой-либо причине не содержит какой-либо информации о производных классах, файл заголовка базового класса не должен включать в себя файлы заголовков производных классов.Таким образом, в действительности нет такой проблемы круговой зависимости, как вы описали.Если определение базового класса содержит некоторую информацию из производных классов, то я предполагаю, что ваш макет иерархии классов действительно неверно спроектирован.

Но я действительно считаю, что вы сформулировали проблему, ичто вы действительно хотите сделать, это другая вещь : создать заголовочный файл, который содержит все интересные (производные) классы, чтобы приложение могло удобно включать только этот единственный заголовочный файл и иметь каждый производный класс 'объявление доступно.То есть какой-то заголовочный файл summary .

И это как раз и есть рекомендуемое решение вашей проблемы.Избегайте путаницы с заголовочным файлом базового класса: просто создайте отдельный файл, включающий заголовочный файл каждого другого производного класса.Таким образом, вы оставляете файлы, относящиеся к иерархии классов, нетронутыми, а также разрешаете, чтобы приложение выборочно включало те или иные объявления классов, не включая все из них.Некоторые хорошо известные библиотеки, такие как Qt, используют этот подход.

2 голосов
/ 06 августа 2011

Похоже, вы пытаетесь создать систему, в которой реализация сокета (raw, udp, tcp) полностью скрыта от конечного пользователя - я полагаю, именно поэтому вы не хотите, чтобы другие заголовочные файлыбыть включенным.

Один из вариантов - просто сделать все методы в вашем сокете чисто виртуальными, а затем скомпилировать каждую реализацию как свой собственный модуль, возвращая только ссылку на базовый класс.Однако вам все равно придется предоставить заводской интерфейс, чтобы можно было создать экземпляр сокета с правильным типом;

Что-то вроде:

socket.h:

    class socket {
      public:
          virtual void send(std::string& data) = 0;
          ....
    };
    socket& factory_socket_tcp(some parameters);
    socket& factory_socket_udp(some parameters);

socket_tcp.cpp:

   class socket_tcp :public socket {
      public:
          virtual void send(std::string& data);
          ....
    };
    socket& factory_socket_tcp(some parameters) {
        socket &s = socket_tcp(....);
        return s;
    }

Или вы можете пойти альтернативным маршрутом pImpl (он же Opaque Pointer), как описано в этом ответе здесь -Непрозрачный указатель имеет то преимущество, что все деталей реализации скрыты внутри файла cpp, так что ничто не просочится в файл .h.Для настоящих общедоступных интерфейсов это обычно предпочтительный вариант

...