Включение файлов .cpp
Я читал в таких местах, как здесь, что вы должны включить файлы .h, а не файлы .cpp, потому что иначе вы получите сообщение об ошибке. Так, например,
main.cpp
#include <iostream>
#include "foop.h"
int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}
foop.h
#ifndef FOOP_H
#define FOOP_H
int foo(int a);
#endif
foop.cpp
int foo(int a){
return ++a;
}
работает, но если я заменю #include "foop.h"
на #include "foop.cpp"
, я получаю сообщение об ошибке (используя Dev С++ 4.9.9.2, Windows):
multiple definition of foo(int)
first defined here
Почему это?
Ответы
Ответ 1
То, что include
выполняет, копирует все содержимое из файла (это аргумент внутри <>
или ""
), поэтому, когда препроцессор завершает свою работу, main.cpp
будет выглядеть так:
// iostream stuff
int foo(int a){
return ++a;
}
int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}
Итак, foo будет определен в main.cpp
, но определение также существует в foop.cpp
, поэтому компилятор "запутывается" из-за дублирования функции.
Ответ 2
Есть много причин препятствовать включению файла .cpp, но это не является строго запрещенным. Ваш пример должен компилироваться.
Вероятно, проблема заключается в том, что вы компилируете как main.cpp, так и foop.cpp, что означает, что две копии foop.cpp связаны между собой. Компилятор жалуется на дублирование.
Ответ 3
Когда вы произнесете #include "foop.cpp"
, вы скопировали все содержимое foop.cpp
и вставили его в main.cpp
.
Поэтому, когда вы компилируете main.cpp
, компилятор испускает main.obj
, который содержит исполняемый код для двух функций: main
и foo
.
При компиляции foop.cpp
сам компилятор испускает foop.obj
, который содержит исполняемый код для функции foo
.
Когда вы связываете их вместе, компилятор видит два определения для функции foo
(один из main.obj
, а другой из foop.obj
) и жалуется, что у вас несколько определений.
Ответ 4
Это сводится к различию между определениями и декларациями.
- Вы можете объявлять функции и переменные несколько раз, в разных единицах перевода или в одной и той же единицы перевода. После объявления функции или переменной вы можете использовать ее с этой точки.
- Вы можете определить нестационарную функцию или переменную только один раз во всех единицах перевода. Определение нестатических элементов более одного раза вызывает ошибки компоновщика.
Заголовки обычно содержат объявления; Файлы cpp содержат определения. Когда вы включаете файл с определениями более одного раза, вы получаете дубликаты во время компоновки.
В вашей ситуации одна дефиниция происходит от foo.cpp
, а другое определение происходит от main.cpp
, которое включает foo.cpp
.
Примечание:, если вы измените foo
на static
, у вас не будет ошибок связывания. Несмотря на отсутствие ошибок, это не очень хорошо.
Ответ 5
Вы должны просто включить заголовочный файл (ы).
Если вы включаете заголовочный файл, заголовочный файл автоматически находит файл .cpp.
- > Этот процесс выполняется LINKER.
Ответ 6
Поскольку ваша программа теперь содержит две копии функции foo
, один раз внутри foo.cpp и один раз внутри main.cpp
Подумайте о #include в качестве инструкции для компилятора, чтобы скопировать/вставить содержимое этого файла в ваш код, чтобы вы получили обработанный файл main.cpp, который выглядит как
#include <iostream> // actually you'll get the contents of the iostream header here, but I'm not going to include it!
int foo(int a){
return ++a;
}
int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}
и foo.cpp
int foo(int a){
return ++a;
}
следовательно, ошибка множественного определения
Ответ 7
Из-за Одно правило определения (возможно, 1).
В С++ каждый не-встроенный объект и функция должны иметь ровно одно определение внутри программы. В #include
файле, в котором определяется foo(int)
(файл CPP), он определяется как в каждом файле, где foop.cpp равен #include
d, так и в foop.cpp(при условии, что foop.cpp скомпилирован).
Вы можете сделать функцию inline
переопределить это поведение, но я не рекомендую это здесь. Я никогда не видел ситуации, когда это необходимо или даже желательно для #include
файла CPP.
Бывают ситуации, когда желательно включить определение чего-то. Это особенно актуально, когда вы пытаетесь отделить определение шаблона от его объявления. В этих случаях я называю файл HPP, а не CPP, чтобы обозначить разницу.
1: "(возможно)" Я говорю, вероятно, потому, что фактический код, который вы опубликовали, должен компилироваться без ошибок, но с учетом ошибки компилятора кажется вероятным, что код, который вы опубликовали, точно так же, как и код, который вы компилируете.
Ответ 8
Использование метода ".h" лучше
Но если вы действительно хотите включить файл .cpp, тогда сделайте foo (int) static в foo.cpp
Ответ 9
Если кто-то, играющий с шаблонным кодом для экспериментов, хочет включить файлы CPP, это можно сделать, исключив включенный файл CPP из этапа компиляции/сборки. Таким образом, компоновщик будет иметь только одно определение.