Подтвердить что ты не робот

Error: класс не был объявлен, несмотря на включение заголовка, а компиляция кода в другом месте

Итак, у меня есть класс, включенный в другой класс, который продолжает бросать ошибку компиляции формы "ошибка:" ПроблемаClass "не была объявлена. Файлы настроены таким образом:

#ifndef PROBLEMCLASS_H
#define PROBLEMCLASS_H

#include <iostream>
#include <cmath>

class ProblemClass
{
  public:

    virtual void Init() = 0;
};

#endif

и класс, в котором происходит ошибка, выглядит следующим образом:

#ifndef ACLASS_H
#define ACLASS_H

#include "problemclass.h"

class AClass : public Base
{
  public:

    void DoSomething(ProblemClass* problem);

};

#endif

Ошибка компиляции возникает при void Dosomething();

Я знаю, что кода здесь недостаточно для решения проблемы. Я не смог создать минимальный пример, который может воспроизвести его. Поэтому мой вопрос гораздо более общий; что это может сделать? Есть ли что-нибудь в частности, которое я должен искать, или какую-то линию запроса, которую я должен отслеживать, чтобы отслеживать ее?

Этот код компилируется в почти идентичной версии проекта.

Помощь любого рода была бы весьма признательна, как бы она ни расплывчата. Я использую codeblocks 10.05 с mingw4.4.1 в win 7 64 бит.

4b9b3361

Ответ 1

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

Вы могли забыть включить problemclass.h из файла, в котором вы используете ProblemClass. Вы можете ошибочно называть имя ProblemClass либо в своем собственном файле заголовка, либо в том месте, где вы его используете. Это может быть трудно обнаружить, если это ошибка капитализации, такая как запись Problemclass или problemClass вместо ProblemClass. Вы могли бы скопировать ваши защитные средства включения #defines из одного файла заголовка в другой и затем забыть изменить определенные имена. Тогда вступит в силу только первый из этих двух файлов заголовков. Вы могли бы разместить ProblemClass в пространстве имен A, и в этом случае вы должны ссылаться на ProblemClass как A:: ProblemClass, если вы ссылаетесь на него вне пространства имен A. Возможно, вы используете шаблоны и не ожидаете, что двухфазный поиск будет работать он. Вы могли бы ошибочно написать имя файла в своем include. Компилятор не сообщит об ошибке, если у вас также есть старая версия этого файла под названием с ошибкой. Вы могли бы сделать ProblemClass макросом, который определяется только после включения проблемыclass.h, и в этом случае то, что вы видите как ProblemClass, заменяется чем-то другим препроцессором макросов. Вы могли бы определить ProblemClass в файле заголовка, отличном от problemclass.h, а затем проблемаclass.h фактически определяет что-то еще.

Ответ 2

У меня было такое же сообщение об ошибке в результате круговой зависимости в моих заголовочных файлах/классах:

foo.hpp:

#ifndef FOO_HPP
#define FOO_HPP

#include <stdio.h>
#include "bar.hpp" // <-- here

class Foo {
public:
    int value = 0;

    void do_foo(Bar myBar) {
        printf("foo + %d\n", myBar.value);
    }
};

#endif //FOO_HPP

bar.hpp:

#ifndef BAR_HPP
#define BAR_HPP

#include <stdio.h>
#include "foo.hpp" // <-- and here

class Bar {
public: 
    int value = 1;      

    void do_bar(Foo myFoo) {
        printf("bar = %d \n", myFoo.value);
    }
};

#endif //BAR_HPP

Компиляция с помощью: g++ -std=c++11 foo.hpp -o foo привела к следующему выводу:

In file included from foo.hpp:5:0:
bar.hpp:11:15: error: ‘Foo’ has not been declared
bar.hpp: In member function ‘void Bar::do_bar(int)’:
bar.hpp:12:32: error: request for member ‘value’ in ‘myFoo’, which is of non-class type ‘int’

Ответ 3

Отправьте команду, которую вы используете для компиляции. Я видел эту проблему, если у вас есть два отдельных файла, которые содержат один и тот же заголовок, и вы делаете gcc *.cpp. Это происходит потому, что #define определяется для всего экземпляра gcc, а не только для каждого скомпилированного отдельного файла объекта.

Ex.

Файл1

#ifndef FILE1_HPP
#define FILE1_HPP 1
....
#endif

Затем два отдельных файла, которые ссылаются на него.

#include <file1.hpp>

Попытка скомпилировать все одновременно приведет к сбою одного из файлов cpp, поскольку FILE1_HPP уже определен (вызывая игнорирование файла заголовка для этого файла cpp).

gcc -Wall *.cpp

Ответ - либо удалить #ifndef, либо скомпилировать каждый файл в свои собственные объектные файлы, а затем связать их с вашим основным приложением.

Ответ 4

Единственное, что я мог подумать, это приведет к ошибке компиляции на основе того, что вы представили, если PROBLEMCLASS_H каким-то образом переопределяется за пределами файла заголовка. Как например:

//main.cpp
#define PROBLEMCLASS_H
#include "aclass.h"

int main() {}

Одна из идей, которую вы можете попробовать, - не включать "problemclass.h" в "aclass.h", а просто переслать объявление ProblemClass. Для этого вам нужно убедиться, что определение AClass содержит только ссылки или указатели на ProblemClass - вы не хотите, чтобы компилятор попытался взять размер ProblemClass, который нуждается в его полном определении.

//aclass.h
#ifndef ACLASS_H
#define ACLASS_H

class ProblemClass;

class AClass : public Base
{
  public:
    void DoSomething(ProblemClass* problem);
};

#endif

Другой метод, который вы можете использовать, чтобы помочь отследить эту проблему заголовка, - это просто обработать проблемную компиляцию .cpp. Откройте предварительно обработанный выходной файл (обычно расширение ".i" ) и проверьте, что на самом деле происходит. Это удобно, особенно если "включает" множество и трудно предсказать.

Ответ 5

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

В вашем случае вы можете определить PROBLEMCLASS_H в некоторых других файлах заголовков. В результате ваш файл cpp пропустит определение в файле заголовка. Другими словами, строка #include "problemclass.h" пропускается.

В моем случае я использую MingW64 под Linux. Скажем, у меня есть файл заголовка IO.h:

// IO.h
#ifndef _IO_H_
#define _IO_H_

class A{
...
};
#endif

В моем файле main.cpp:

// main.cpp
#include <unistd.h>
#include "IO.h"
int main(int argc, char** argv) {
 //...
}

Файл cpp выглядит невиновным. Однако, когда unistd.h включен, он тайно включает /usr/i686-w64-mingw32.static/include/io.h, поставляемый MingW, и этот io.h выглядит следующим образом:

// io.h
#ifndef _IO_H_
#define _IO_H_
...
#endif /* End _IO_H_ */

Теперь вы можете видеть, что включение unistd.h приведет к включению io.h из MingW, и это скроет мой собственный IO.h. Я думаю, что подобная проблема, как ваша.

Если вы переключите порядок включений (поместите #include <unistd.h> после IO.h), программа скомпилирует. Но это не хорошее предложение. Я рекомендую вам не использовать _IO_H_ для защиты своего IO.h.

Чтобы понять, как и почему ваш PROBLEMCLASS_H включен, я согласен с @greatwolf, вы можете использовать g++ -E для вывода вывода препроцессора и вручную изучить его. Проверьте, какие файлы включены до вашего PROBLEMCLASS_H и в каком порядке они включены. Надеюсь, это поможет решить вашу проблему.

Ответ 6

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

EG:

Заголовок

class SomeClass
{
public:
    void SomeFunc();
private:
    typedef int SomeType_t;
};

Источник (будет выдавать ошибку SomeType_t не определен)

void SomeFunc()
{
    SomeType_t dummy = 0;
}

Источник (исправлено)

void SomeClass::SomeFunc()
{
    SomeType_t dummy = 0;
}

Это глупая, но очень простая ошибка, чтобы сделать и не видеть, пока вы не дадите себе три сотрясения, ударив головой о стол.

Ответ 7

У меня была та же проблема, и я обнаружил, что я делаю неправильно: после вашего примера я включил ProblemClass в класс ACLC, что вызвало проблему.