Почему учебник Qt создает класс заголовка следующим образом? [Дубликат]

Это означает, что указанная переменная не указана ни на что. Я мог бы сгенерировать это так:

SqlConnection connection = null;
connection.Open();

Это вызовет ошибку, потому что, пока я объявил переменную «connection», она не указала ни на что. Когда я пытаюсь вызвать член «Open», для его устранения нет ссылки, и он будет вызывать ошибку.

Чтобы избежать этой ошибки:

  1. Всегда инициализируйте свои объекты, прежде чем пытаться что-либо с ними делать.
  2. Если вы не уверены, что объект имеет значение null, проверьте его с помощью object == null.

Инструмент Resharper JetBrains определит каждое место в вашем коде, которое имеет возможность ошибки нулевой ссылки, позволяя вам ввести нулевую проверку. Эта ошибка является источником ошибок номер один, IMHO.

3
задан Xeo 17 April 2011 в 17:21
поделиться

9 ответов

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

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

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

10
ответ дан Michael Aaron Safyan 26 August 2018 в 07:27
поделиться

Это называется форвардной декларацией. Тело класса 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
ответ дан Amarghosh 26 August 2018 в 07:27
поделиться

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

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;
}
1
ответ дан aschepis 26 August 2018 в 07:27
поделиться

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

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

0
ответ дан AshleysBrain 26 August 2018 в 07:27
поделиться

Любопытно, зачем нам вообще нужно выражение forward ? Не является ли декларацией для перехода просто декларацией (в отличие от определения)?

class X;  // declaration

class X   // definition
{
    int member;
    void function();
};
1
ответ дан fredoverflow 26 August 2018 в 07:27
поделиться

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

2
ответ дан Jesper 26 August 2018 в 07:27
поделиться

Это называется форвардным объявлением. Он используется, чтобы ваш код знал, что класс 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
ответ дан raph.amiard 26 August 2018 в 07:27
поделиться

Попытайтесь написать это:

file bar.h:

        #include "bar.h"

        class Foo
        {
        Bar* bar_ptr;
        }

file foo.h:

        #include "foo.h"

        class Bar
        {
            Foo* foo_ptr;
        }

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

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

        class Bar;

        class Foo
        {
        Bar* bar_ptr;
        };

file foo.h:

        class Foo;

        class Bar
        {
            Foo* foo_ptr;
        };
0
ответ дан SF. 26 August 2018 в 07:27
поделиться

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

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

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

0
ответ дан sharptooth 26 August 2018 в 07:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: