Как переслать объявление структуры, используемой в качестве переменной-члена - PullRequest
3 голосов
/ 04 августа 2011

У меня есть структура с именем CardState, определенная в Application.h :

#ifndef APPLICATION_H
#define APPLICATION_H

#include <Session.h> // Note that both files include each others

struct CardState {
    bool property1;
    bool property2;
};

class Application : public QApplication {

    Q_OBJECT

public:

    explicit Application(int argc, char *argv[]);

}

Затем я использую этот тип CardState в другом файле:

#ifndef SESSION_H
#define SESSION_H

#include <Application.h>

struct CardState;

class Session : public QObject {

    Q_OBJECT

public:

    void setCardState(const CardState& cardState);
    CardState cardState() const;

private:

    CardState cardState_;

};

}
#endif // SESSION_H

В момент включения Session.h кажется, что Application.h еще не был включен, поэтому мне нужно переслать объявление структуры (см. Выше).Однако этого недостаточно, после добавления предварительного объявления я все еще получаю эту ошибку:

'Session::cardState_' uses undefined struct 'CardState'

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

Ответы [ 3 ]

4 голосов
/ 04 августа 2011

Согласно комментарию Оли Чарльзворта, это должно работать как есть.

В общем случае вы бы хотели:

  • Поместите CardState в его собственный заголовок и затем #include его во все заголовки "client", таким образом избегая любых сложностей, которые могут возникнуть из-за порядка следования этих заголовков.
  • Объявите Session::cardState_ как (умный) указатель и избегайте необходимости в фактическом CardState объявлении.

- РЕДАКТИРОВАТЬ ---

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

1 голос
/ 04 августа 2011

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

Как только вы отправите объявление, компилятор узнает только, что тип существует; у него нет никакой информации о его размере, членах или методах. он называется Неполный тип . Следовательно, вы не можете использовать этот тип (тип Incomlpete) для объявления члена или базового класса, поскольку компилятор должен знать макет типа.

Так что да, вам нужно сделать указатель типа Incomplete.

1 голос
/ 04 августа 2011

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

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

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

В комментариях вы говорите, что исходное сообщение об ошибке было что-то вроде «не удалось найти заголовок».Для меня это означает, что у вас, вероятно, нет каталога, содержащего Application.h, в стандартной библиотеке поиска вашего компилятора.Вы можете добавить его с помощью директивы -I dirname в командной строке, если хотите.Но, скорее всего, он находится в том же каталоге, что и ваш другой файл включения, и вы можете просто изменить оператор включения на следующий, и он будет найден:

#include "Application.h"  // Note quotes instead of <> 

Обновление : Лоран обновляет код примера и специально спрашивает в комментариях ниже об указателях.

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

Если у вас действительно есть взаимно ссылающиеся структуры, тогда да, вам нужно будет заполнить хотя бы одно из этих полейлибо указатель, либо ссылка.Это не совсем для компилятора, так как физически возможно реализовать структуру (и).Если A физически содержит полную копию B, а B физически содержит полную копию A, то ваша структура будет логически иметь бесконечный размер!

...