Заголовок g ++ включен: определение не найдено - PullRequest
1 голос
/ 22 марта 2009

Добрый вечер:)

Я играю с g ++ и makefiles. Я дошел до этой точки:

foo.h:

#ifndef _FOO_H_
#define _FOO_H_

#include "bar.h"

class foo {
private:
    bar something;
public:
    bool start();
    bool stop();
};

#endif // _FOO_H_

Foo.h в конечном итоге включается в мой основной cpp-файл, поэтому я могу привести его в движение, вызвав start / stop.

void somewhere() {
    foo* hihi = new foo;
    hihi->start();
    delete hihi;
}

Тогда есть bar.h:

#ifndef _BAR_H_
#define _BAR_H_

class bar {

};

#endif // _BAR_H_


Однако g ++ это не нравится:

g++  (some_flags) -c main.cpp
In file included from main.cpp:2:
foo.h:8: error: ‘bar’ does not name a type

Я использую make-файлы и пробовал сочетание таких вещей, как:

main.o: main.cpp foo.h bar.h

Даже если я не думаю, что мне нужно добавлять сюда bar.h, разве этого не должно быть достаточно для включения в foo.h?

Чтобы уточнить, это примерно так, как это сейчас настроено (да, я знаю, это можно сделать более эффективным способом):

main.o: main.cpp foo.h
    $(CC) $(CFLAGS) -c main.cpp

foo.o: foo.h foo.cpp
    $(CC) $(CFLAGS) -c foo.cpp

bar.o: bar.h bar.cpp
    $(CC) $(CFLAGS) -c bar.cpp

Что происходит? Я полагаю, что в g ++ мне чего-то не хватает, и то, как он обрабатывает заголовки, укажите мне правильное направление, пожалуйста!

edit - нашел решение:

Doh! Я чувствую себя тупым прямо сейчас. Возился с boost :: asio и вроде как забыл, я все еще оставил это где-то на верху моих заголовков: используя boost :: asio :: ip :: tcp;

Скажем так, есть функция boost :: asio :: ip :: tcp :: bar: D

Ну да ладно, все равно спасибо!

Ответы [ 4 ]

2 голосов
/ 22 марта 2009

Возился с boost :: asio и вроде как забыл, я все еще где-то оставил это поверх моих заголовков: используя boost :: asio :: ip :: tcp;

Скажем так: есть функция boost :: asio :: ip :: tcp :: bar

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

Что ж, вы столкнулись с реальной ситуацией, когда определение типа класса, возможно, помогло бы вам найти вашу проблему немного легче:

 class bar {
 // ...
 };
 typedef class bar bar;

Генерирует это более значимое сообщение, если уже существует функция с именем bar():

In file included from C:\temp\foo.h:4,
                 from C:\temp\test.cpp:4:
C:\temp\bar.h:7: error: `typedef class bar bar' redeclared as different kind of symbol
C:\temp\test.cpp:1: error: previous declaration of `void bar(int)'
C:\temp\bar.h:7: error: declaration of `typedef class bar bar'
2 голосов
/ 22 марта 2009

Дважды проверьте все. Если вы включите bar.h в foo.h, компилятор не должен выдавать ошибку. Вы включаете foo.h из bar.h? Лучше не делать этого, потому что это вызовет круговую зависимость между заголовками, что приведет к таким ошибкам.

Также проверьте правильность написания заголовков. Это может быть распространенным источником раздражения:

#ifdef _BAR_H_ // OOPS! we wanted #ifndef
#define _BAR_H_

class bar {

};

#endif // _BAR_H_

Кроме того, вам не следует ставить подчеркивание перед именем макроса охранника заголовка. Эти имена зарезервированы для компилятора. Назовите это INCLUDED_BAR_H или просто BAR_H_ вместо этого.

1 голос
/ 22 марта 2009

Томми Хуэй и Литб уже указали на две вероятные причины; вот некоторая справочная информация, которая, мы надеемся, будет полезна.

Во-первых, это не имеет ничего общего с make-файлами. Makefile - это просто удобная вещь, которая вызывает g ++ для вас, ничего более.

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

  • A #include - это не что иное, как операция копирования / вставки, вставка содержимого включенного файла в этот момент.
  • Все должно быть объявлено , прежде чем оно будет использовано. Иногда, когда возникают циклические зависимости, вам может потребоваться предварительно объявить класс (например, class bar;) в другом заголовке.
  • Если в момент использования требуется больше информации о типе, чем просто о его существовании, то необходимо также определение типа . Это касается, например, вызов метода для объекта этого типа, но также для включения поля этого типа! (Однако не для указателя на объект этого типа, потому что все указатели имеют одинаковый размер.)
0 голосов
/ 22 марта 2009

В main.cpp вам нужно добавить следующую строку вверху файла:

#include "foo.h"
...