Включить в заголовочный файл против forward-declare и включить в .cpp

У меня есть класс B, и я хочу называть участников формой класса A. Итак:

1.

//A.h    
class B; 
class A 
{ 
private:
    B* m_p; 
}; 

//a.cpp
#include "B.h"

2.

// A.h
#include "B.h"

class A 
{ 
private: 
    B * impl_; 
}; 

в каком направлении лучше, и является ли это двумя аналогичными, когда участвует небольшой проект с не слишком большой зависимостью?

Ответы

Ответ 1

Ваш первый способ сделать это означает, что в a.h известно существование class B, но не его определение. Это ограничивает возможности B внутри a.h. Например, вы можете иметь переменные типа B *, но не переменные типа B (потому что для объявления переменной типа B компилятор должен уметь видеть полное определение B). Кроме того, если у вас есть переменные типа B *, вы не можете разыменовывать указатель (потому что для этого также должно быть определено определение B).

Поэтому ваш второй выбор - ndash; который не имеет этих проблем – является предпочтительным, и это то, что большинство людей используют большую часть времени.

Это только особые случаи, когда первый метод может быть полезен. Например:

  • Если файлы .h включают друг в друга (но тогда вы можете получить ряд дополнительных проблем, а также относительно включения-защиты, это, как правило, сложно и следует избегать);
  • Если b.h является чрезвычайно большим и сложным, вы можете не включать его везде, где это возможно, потому что это замедляет процесс компиляции.

Ответ 2

Ваш первый метод - это форвардное объявление. Вторая часть включает класс B.

Когда использовать один над другим?

Использовать первый, когда:

  • В определении для A вы имеете только указатель на B, т.е. не являетесь членом B.
  • Вы никогда не вызываете какую-либо функцию B из определения A. (т.е. все вызовы функций-членов из B происходят в файле .cpp, где вы фактически реализуете функции-члены.)
  • Вы ожидаете, что интерфейс или размер класса B будут меняться часто, но не интерфейс A. Таким образом, если B изменяется, только содержимое a.cpp будет перекомпилировано, но ah (и другие файлы, которые включают ah) не нужно изменять.

Использовать второй, когда:

  • Вам нужно знать размер of B. Компилятор вычисляет размер класса, используя его определение класса и размеры всех его членов. Например, если класс A имеет член, который имеет тип B, то для вычисления размера A компилятор должен знать размер B; чтобы узнать размер B, вам нужно включить b.h.
    • Вам нужно вызвать функции класса B. Чтобы узнать, действительно ли вы вызываете фактически существующие функции, компилятору необходимо знать интерфейс класса B, т.е. вам нужно включить b.h.

Ответ 3

Ответ: 1.
Взгляните на http://www.umich.edu/~eecs381/handouts/handouts.html

Руководство по файлам заголовка файла

Руководства по файлам заголовков на С++ (Дэвид Кирас, Департамент EECS, Мичиганский университет) говорит:

Руководящий принцип № 10. Если будет выполнено неполное объявление типа X, используйте вместо #, включая заголовок X.h. Если другая структура или класс тип X отображается только как указатель или ссылочный тип в содержимом файл заголовка, то вы не должны # включить X.h, но просто поместите неполная декларация X (также называемая "форвардной" декларацией) рядом начало файла заголовка, как в: class X; См. раздаточный материал Неполные декларации для более подробного обсуждения этого мощного и ценная техника. Обратите внимание: стандартная библиотека включает заголовок неполных деклараций, которые часто бывают достаточными для <iostream>библиотеки, названной <iosfwd>. #include <iosfwd>, когда это возможно, потому что файл заголовка <iostream> чрезвычайно велик (гигантские шаблоны!).

Ответ 4

Просто объявите класс в заголовке класса A.

class B;

Ответ 5

Второй лучше. Это делает класс B модулем, который вы используете с помощью файла .h. Рассмотрим случай, когда вы подкласс B в будущем, и вы обновите A, чтобы использовать C. Во втором случае вы заменяете только заголовок #include и A. В первом случае вам нужно изменить форвардную декларацию. Кроме того, во втором случае вы определяете больше, чем просто символ B.

И как в комментариях, вы должны использовать #include "B.h", если заголовочный файл находится в том же каталоге, что и остальная часть кода.

Ответ 6

Хорошо, что вы делаете, называется форвардным объявлением, причина, по которой вы хотите, - это то, что у вас есть что-то вроде класса A, который использует класс B и ALSO класса B, который использует класс A.

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