C ++, включая файл ".h", путаница с дублированием функций - PullRequest
4 голосов
/ 17 мая 2011

В настоящее время я пишу программу и не могу понять, почему я получил ошибку (примечание: я уже исправил ее, мне интересно, ПОЧЕМУ была ошибка и что это означает, включая файлы .h).

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

Текущий файл, с которым я работаю, я назову Current.cc (который является реализацией Current.h).

Current.cc включал заголовочный файл с именем CalledByCurrent.h (с которым связана реализация, называемая CalledByCurrent.cc).CalledByCurrent.h содержит определение класса.

В CalledByCurrent.cc была определена неклассовая функция с именем thisFunction().thisFunction() не был объявлен в CalledByCurrent.h, так как на самом деле он не был функцией-членом класса (просто маленькая вспомогательная функция).В Current.cc мне нужно было использовать эту функцию, поэтому я просто переопределил thisFunction() в верхней части Current.cc.Однако, когда я сделал это, я получил сообщение об ошибке, сообщив, что функция была дублирована.Почему это так, когда myFunction() даже не было объявлено в CalledByCurrent.h?

Таким образом, я просто удалил функцию из Current.cc, теперь предполагая, что Current.cc имел доступ к thisFunction() из CalledByCurrent.cc.Однако когда я сделал это, я обнаружил, что Current.cc не знал, о какой функции я говорил.Какого черта?Затем я скопировал определение функции для thisFunction() в начало моего CalledByCurrent.h файла, и это решило проблему.Не могли бы вы помочь мне понять это поведение?В частности, почему он подумал, что был дубликат, но он не знал, как использовать оригинал?

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

Ответы [ 6 ]

4 голосов
/ 17 мая 2011

Вы получаете несколько определений от компоновщика - он видит две функции с одинаковым именем и жалуется. Например:

// a.cpp
void f() {}

// b.cpp
void f() {}

тогда

g++ a.cpp b.cpp

дает:

C:\Users\neilb\Temp\ccZU9pkv.o:b.cpp:(.text+0x0): multiple definition of `f()'

Обходной путь - это поместить определение только в один файл .cpp или объявить одну или обе функции как статические:

// b.cpp
static void f() {}
3 голосов
/ 17 мая 2011

Вы не можете иметь две глобальные функции с одинаковым именем (даже в 2 разных единицах перевода). Чтобы избежать ошибки компоновщика, определите функцию как static, чтобы она не видна за пределами блока перевода.

EDIT

Вы можете использовать функцию в другом файле .cpp, используя ключевое слово extern. Смотрите этот пример:

//Test.cpp

void myfunc()
{

}

//Main.cpp
extern void myfunc();
int main()
{
    myfunc();
}

Он будет вызывать myfunc(), определенный в test.cpp.

1 голос
/ 17 мая 2011

Это потому, что всякий раз, когда вы просто объявляете функцию, она рассматривается в extern (глобальной) области (независимо от того, объявляете ли вы ее в заголовочном файле или нет). Линкер будет иметь несколько реализаций для одной и той же сигнатуры функции.

Если эти функции действительно вспомогательные функции, объявите их как;

static void thisFunction();

Иначе, если вы используете ту же функцию, что и помощник, просто объявите ее в общем заголовочном файле, скажем:

//CalledByCurrent.h  (is included in both .cc files)
void thisFunction();

И реализуют thisFunction () в любом из файлов .cc . Это должно правильно решить проблему.

1 голос
/ 17 мая 2011

Механизм включения файла заголовка должен допускать дублирование включений файла заголовка.

0 голосов
/ 17 мая 2011

Имеются 2 отчетливые ошибки, возникающие на 2 разных этапах сборки.

В первом случае, когда у вас есть дубликат, COMPILER доволен, но LINKER жалуется, потому что, когда он собирает всеопределения функций в разных исходных файлах, которые он замечает 2, называются одинаково.Как указано в других ответах, вы можете использовать статическое ключевое слово или общее определение.

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

Перед компиляцией происходит компиляция, поэтому КОМПИЛЕР не может заранее узнать, найдет ли LINKER подходящую функцию, поэтому вы используете объявления, чтобы уведомить Компилятор о том, что определениебудет найден LINKER позже.

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

0 голосов
/ 17 мая 2011

Вот несколько идей:

  • Вы не поместили заголовок , включающий охрану в файл заголовка.Если его включить дважды, вы можете получить ошибку такого рода.
  • Прототип функции (вверху) не соответствует ее сигнатуре 100%.
  • Вы поместили тело функции в заголовочном файле.
  • У вас есть две функции с одинаковой подписью в двух разных исходных файлах, но они не помечены static.

Если вы используете gcc (вы не сказали, какой компилятор вы используете), вы можете использовать переключатель -E для просмотра выходных данных препроцессора.Это включает в себя расширение всех #define с и включение всех #include с.

Каждый раз, когда что-то раскрывается, оно сообщает вам, в каком файле и строке оно было. Используя это, вы можете увидеть, где определено thisFunction().

...