Ошибка прямого объявления вложенных классов С++

Я пытаюсь объявить и использовать класс B внутри класса A и определить B вне A.
Я точно знаю, что это возможно, потому что Бьерн Страуструп
использует это в своей книге "Язык программирования C++"
(стр. 293, например, классы String и Srep).

Итак, это мой минимальный фрагмент кода, который вызывает проблемы

class A{
struct B; // forward declaration
B* c;
A() { c->i; }
};

struct A::B { 
/* 
 * we define struct B like this becuase it
 * was first declared in the namespace A
 */
int i;
};

int main() {
}

Этот код дает следующие ошибки компиляции в g++:

tst.cpp: In constructor ‘A::A()’:
tst.cpp:5: error: invalid use of undefined type ‘struct A::B’
tst.cpp:3: error: forward declaration of ‘struct A::B’

Я попытался просмотреть FAQ по C++, и я получил следующее: здесь и здесь, но
они не относятся к моей ситуации.
Я также прочитайте это отсюда, но это не решает мою проблему.

И gcc, и MSVC 2005 выдают ошибки компилятора по этому поводу.


person xxxxxxx    schedule 21.11.2008    source источник


Ответы (4)


Определите конструктор для A ПОСЛЕ определения структуры B.

person Paul Sonier    schedule 21.11.2008
comment
Конструктор определяется после объявления B. Его необходимо определить после определения B. - person Steve Jessop; 22.11.2008
comment
Обновлено, чтобы заменить объявление определением. :-) - person Paul Sonier; 25.11.2008

Выражение c->i разыменовывает указатель на struct A::B, поэтому в этой точке программы должно быть видно полное определение.

Самое простое решение — сделать конструктор A не встроенным и предоставить для него тело после определения struct A::B.

person CB Bailey    schedule 21.11.2008
comment
Или определите функцию как встроенную, используя ключевое слово inline после определения структуры B. - person Phlucious; 07.02.2013

Это хороший пример того, почему вы хотите хранить определения отдельно от объявлений. Вам нужно изменить порядок вещей, чтобы конструктор A::A() определялся после определения struct A::B.

class A
{
    struct B;
    B* c;
    A();
};

struct A::B
{
    int i;
};

A::A() { c->i; }

int main()
{
    return 0;
}
person e.James    schedule 21.11.2008

Интересно, что я столкнулся с той же проблемой на странице 293 («11.12 A String Class»), упомянутой в книге Страуструпа.

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

class String {
  // ...
  void check(int i) const { if (i<0 || rep->sz <=i) throw Range(); }
  char read(int i) const { return rep->s[i]; }
  void write(int i, char c) { rep=rep->get_own_copy(); rep->s[i]=c; }
  ...etc...

Я немного погуглил и нашел последнюю авторскую реализацию этого класса String, доступную здесь: http://www2.research.att.com/~bs/string_example.c

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

person Conan the Fishmonger    schedule 19.10.2010