класс фу; в заголовочном файле - PullRequest
3 голосов
/ 28 апреля 2010

Кто-нибудь может объяснить, почему заголовочные файлы имеют что-то вроде этого?

class foo; // This here?
class bar
{
   bar();

};

Нужно ли включать оператор при использовании этого?

Спасибо.

Ответы [ 9 ]

10 голосов
/ 28 апреля 2010

Первое class foo; называется предварительным объявлением класса foo. Он просто сообщает компилятору, что он существует и что он называет класс. Это делает foo так называемым «неполным типом» (если полная декларация foo уже не была замечена). С неполным типом вы можете объявить указатели этого типа, но вы не можете выделить экземпляры этого типа или сделать что-либо, что требует знания его размера или членов.

Такие предварительные объявления часто используются, когда два типа могут иметь указатели друг на друга, и в этом случае оба должны иметь возможность выражать понятие указателя на другой тип, и поэтому у вас будет циклическая зависимость без такого вещь. Это необходимо в основном потому, что в C ++ для разрешения типов используется механизм однократного прохода; в Java вы можете иметь циклические зависимости без предварительных объявлений, потому что Java использует несколько проходов. Вы также можете увидеть предварительные объявления, когда у автора ложное впечатление, что использование предварительных объявлений вместо включения требуемого заголовка сокращает время компиляции; это, конечно, не так, потому что в любом случае вам необходимо включить полное объявление (то есть заголовок), и если используются средства защиты препроцессора, то во времени компиляции практически нет различий.

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

2 голосов
/ 28 апреля 2010

Это предварительное объявление . Это нужно, например, если в строке классов есть указатель на объект foo, но вы не хотите сразу же включать полное определение объекта foo.

1 голос
/ 28 апреля 2010

Просто любопытно, зачем нам вообще нужен термин форвардная декларация ?Разве предварительная декларация не является декларацией (в отличие от определения)?

class X;  // declaration

class X   // definition
{
    int member;
    void function();
};
1 голос
/ 28 апреля 2010

это предварительное объявление класса. По моему опыту, это обычно делается, когда у вас круговая зависимость .. например

in foo.h
--------
#include "bar.h"

class foo
{
public:
    foo(bar *bar);
private:
    foo *m_foo;
};

and in bar.h
------------
class foo;
class bar
{
public:
    void methodFooWillCall();
protected:
    std::list<foo *> myFoos;
}
0 голосов
/ 28 апреля 2010

Попробуйте подумать о написании этого:

файл bar.h:

        #include "bar.h"

        class Foo
        {
        Bar* bar_ptr;
        }

файл foo.h:

        #include "foo.h"

        class Bar
        {
            Foo* foo_ptr;
        }

Это не будет работать, сначала из-за бесконечной цепочки #include, затем, если вы избавитесь от одного из включений, либо Foo не будет знать, что такое Bar, либо Bar не будет знать, что такое Foo. *

Попробуйте вместо этого:

        class Bar;

        class Foo
        {
        Bar* bar_ptr;
        };

файл foo.h:

        class Foo;

        class Bar
        {
            Foo* foo_ptr;
        };
0 голосов
/ 28 апреля 2010

Это называется предварительным объявлением. Он используется, чтобы ваш код знал, что класс foo существует. Это, в свою очередь, может использоваться панелью классов.

Обычно используется для решения проблем с циркуляром. Возьмите это к примеру

//a.h
#include "b.h"

class A
{
    void useB(B obj);
}

и

// b.h
#include "a.h"
class B
{
     void useA(A obj);
}

Это вызывает проблему кругового включения, потому что a.h включает в себя b.h, который в свою очередь включает в себя a.h до бесконечности. Вы можете решить эту проблему, сделав предварительное объявление каждого класса в каждом заголовке, например:

//a.h
class B;

class A
{
    void useB(B obj);
}

// b.h
class A;

class B
{
     void useA(A obj);
}

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

0 голосов
/ 28 апреля 2010

Это называется предварительным объявлением. Тело класса foo будет определено в более поздней части файла. Предварительное объявление выполняется для обхода циклических зависимостей: для определения класса Bar требуется класс Foo и наоборот.

class Bar
{
   Foo * foo;
};
class Foo
{
   Bar * bar;
};

Как видите, Bar имеет ссылку на Foo и наоборот. Если вы попытаетесь скомпилировать это, компилятор будет жаловаться, что он ничего не знает о Foo. Решением является прямое объявление class Foo над Bar (точно так же, как вы объявляете прототип функции выше main и определяете ее тело позже).

class Foo; //Tells the compiler that there is a class Foo coming down the line.
class Bar
{
   Foo * foo;
};
class Foo
{
   Bar * bar;
};
0 голосов
/ 28 апреля 2010

Это предварительное объявление класса 'foo'.Он позволяет вам объявлять указатели и ссылки на класс, но не использовать его (например, вызывать членов или определять его размер), потому что он еще не определен!Позднее за ним должно следовать полное нормальное объявление (class foo { ... };).

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

0 голосов
/ 28 апреля 2010

Это предварительная декларация. Рассмотрим следующий пример:

class foo; // you likely need this for the code beneath to compile
class bar {
    void smth( foo& );
};

Если вы не включили определение class foo таким образом, чтобы компилятор видел его до компиляции определения class bar, код не скомпилируется (компилятор скажет, что не знает, что foo означает), если у вас нет предварительной декларации.

...