Избегание круговых зависимостей файлов заголовков - программирование
Подтвердить что ты не робот

Избегание круговых зависимостей файлов заголовков

Есть ли у вас хороший совет, как избежать круговых зависимостей файлов заголовков, пожалуйста?

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

Есть ли общие, проверенные и рабочие правила? Спасибо.

4b9b3361

Ответ 1

Если у вас есть круговая зависимость, вы делаете что-то неправильно.

Как например:

foo.h
-----
class foo {
public:
   bar b;
};

bar.h
-----
class bar {
public:
   foo f;
};

Возможно, вы незаконны:

foo.h
-----
class bar; // forward declaration
class foo {
   ...
   bar *b;
   ...
};

bar.h
-----
class foo; // forward declaration
class bar {
   ...
   foo *f;
   ...
};

И это нормально.

Общие правила:

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

Ответ 2

  • Использовать форвардные объявления, где это возможно.
  • Перемещение любого заголовка включает из файла заголовка и в соответствующий файл cpp, если они необходимы только для файла cpp. Самый простой способ обеспечить это - сделать #include "myclass.h" первым включением в myclass.cpp.
  • Знакомство с интерфейсами в точке взаимодействия между отдельными классами может помочь уменьшить зависимости.

Ответ 3

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

См. также Лучшая практика круговой зависимости

Ответ 4

Некоторые рекомендации, которые я придерживаюсь, чтобы избежать круговых зависимостей,

  • Придерживайтесь принципов OOAD. Не включайте заголовочный файл, если только класс не включен в составное отношение к текущему классу. Вместо этого используйте форвардную декларацию.
  • Разработайте абстрактные классы, чтобы действовать как интерфейсы для двух классов. Сделайте взаимодействие классов через этот интерфейс.

Ответ 5

в зависимости от ваших возможностей препроцессора:

#pragma once

или

#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif

Если вам очень скучно разрабатывать заголовочные файлы, возможно, makeheaders от Hwaci (разработчики SQLite и ископаемого DVCS) могут представлять интерес для вы.

Ответ 6

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

Ответ 7

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

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

Тогда вы почти наверняка не ошибетесь.

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

По этой причине я бы сказал: будьте осторожны с шаблонами! В идеале шаблон не должен включать ничего в свой код реализации.

Ответ 8

Altough Artyom предоставил лучший ответ, этот урок также замечателен и предоставляет некоторые расширения http://www.cplusplus.com/forum/articles/10627/