Простой вопрос о заголовочных файлах в C ++ - PullRequest
2 голосов
/ 29 июля 2011

Допустим, у меня есть 3 файла: add.h, add.cpp и main.cpp. Это распространенный пример на обучающих сайтах C ++, где add.h содержит прототип функции под названием «add». Add.cpp содержит объявление прототипа, а main.cpp включает add.h, а затем вызывает функцию add () для добавления двух чисел (x и y) вместе.

Мой вопрос таков: независимо от того, что я называю add.cpp, моя программа работает просто отлично. Elephant.cpp работает так же хорошо, как doctorWhoRules.cpp. Обрабатывает ли компилятор все локальные файлы .cpp, чтобы найти данный прототип в add.h? Я не объявляю имя файла .cpp, который его содержит. Я просто не понимаю, как это работает.

Спасибо!

Ответы [ 6 ]

2 голосов
/ 29 июля 2011

Имена являются соглашением. Вы можете назвать его как угодно, включая «еженедельник». Вам не нужно использовать «add.cpp».

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

Например, очень сбивает с толку, когда люди используют файлы "foo.cpp", как если бы они были заголовочными файлами! Тем не менее, это разрешено в C ++. Это, однако, против соглашения, и программирование достаточно сложно, как оно есть.

2 голосов
/ 29 июля 2011

Я думаю, вы смешиваете Java с C++. В Java (редакторы, такие как Eclipse) есть общее ограничение: ваше class имя должно совпадать с именем файла. т.е.

// Add.java
class Add
{
}

В C ++ таких ограничений нет. Ваше имя файла может быть любым значимым именем. Единственное, о чем вам нужно позаботиться, это то, что ваши файлы реализации имеют расширения .cpp / .cxx / .C и т. Д. (Я не знаю, поддерживают ли современные компиляторы иное, кроме этого).

Даже ваш заголовочный файл может быть любым произвольным расширением, кроме .cpp и всего; более обычные расширения для заголовочных файлов: .h, .hpp и т. д.

1 голос
/ 29 июля 2011

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

Смысл прототипов в файле .h - просто сделать его доступным для компилятора, когда он компилирует main.cpp, точные типыи имена, которые на самом деле определены в add.cpp (или как вы его называете).Это позволяет выполнять часть компиляции, фактически не видя файла реализации.

Тем не менее, шаблоны нарушают эту модель "отдельной компиляции", поскольку компилятор должен видеть полное определение шаблона во время компиляция, поскольку она должна генерировать специфичный для класса код в зависимости от того, как вызывается шаблон.Обычно шаблоны помещаются в файлы .h и включаются везде.

1 голос
/ 29 июля 2011

Различные возможности;

1) Вы на самом деле не переименовываете файл, вы просто сохраняете файл под новым именем - и старый add.cpp все еще там и работает.

2) Существует старый add.obj, и это то, что связывается

3) Файлы открываются как проект, и Visual-Studio выясняет, что открытые файлы - это действительно все файлы, в которые вы хотите скомпилировать и выполнить

1 голос
/ 29 июля 2011

См. Выше ответы для имен файлов. Компоновщик собирает объектные файлы, сопоставляет код и т. Д. И создает ваш исполняемый файл.

0 голосов
/ 29 июля 2011

Допустим, у нас есть add.h add.cpp и main.cpp.

Вам нужен прототип add как в main.cpp, так и в add.cpp. Это нужно main.cpp, потому что он хочет использовать класс add, а это нужно add.cpp, потому что он хочет реализовать его, поэтому нужен его прототип. Это делается, как вы знаете, путем включения файла заголовка. Выполнение #include «add.h» в add.cpp и main.cpp.

Теперь компилятор вступает в действие, создает два объектных файла, а именно main.o и add.o. Так что пока главный знает только о add, внутренней механики (реализации) еще нет. После этого компоновщик объединяет main.o и add.o в исполняемый файл, в котором есть все навороты и свистки, которые запускает add из main.

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

Перед компилятором у нас есть еще один шаг, который называется предварительной обработкой. На этом шаге выполняется копирование содержимого файлов после # include.

Независимо от того, как вы называете add.h, это не имеет значения, но вы должны включить правильный файл в main.cpp и add.cpp. Независимо от того, как вы вызываете add.cpp или main.cpp, не имеет значения, только ваш компилятор должен быть проинструктирован о том, как они вызываются. Например, в Visual Studio это делается автоматически, переименовывая их в файле проекта. Если вы используете gcc, вы должны сами указать свой компилятор и компоновщик В этой конкретной ситуации вы делаете следующее.

скомпилируйте add.cpp в add.o:

gcc -c add.cpp

скомпилировать main.cpp в main.cpp:

gcc -c main.cpp

ссылка add.o и main.o в myniceprogram:

gcc -o myniceprogram add.o main.o
...