Урок №20. Многофайловые программы

  Юрий  | 

    | 

  Обновл. 7 Мар 2019  | 

 26944

 ǀ   30 

Как только программы становятся больше, их следует разбивать на несколько файлов (в целях удобства и улучшения функциональности). Одним из преимуществ использования IDE является лёгкость в работе с n-ым количеством файлов. Мы уже знаем, как создавать и компилировать однофайловые проекты, добавление новых файлов не составит труда.

Добавление файлов к проекту в Visual Studio 2017

В Visual Studio 2017 щёлкните правой кнопкой мыши по имени вашего проекта в «Обозревателе решений», затем «Добавить» > «Создать элемент…»:

Во всплывающем диалоговом окне выберите тип файл, укажите его имя, расположение, а затем нажмите «Добавить»:

Также вы можете добавлять файлы к вашему проекту через «Проект» > «Добавить новый элемент…»:


Добавление файлов к проекту в Code::Blocks


В Code::Blocks перейдите в «File» > «New» > «File…»:

Затем выберите «C/C++ source» и нажмите «Go»:

Затем «Next» (это окно может быть, а может и не быть):

Затем «C++» и опять «Next»:

Затем укажите имя новому файлу (не забудьте расширение .cpp) и его расположение (нажмите троеточие и выберите путь). Убедитесь, что поставлены все три галочки (они отвечают за конфигурации сборки). Затем нажмите «Finish»:

Готово! Файл добавлен.

Добавление файлов к проекту в GCC/G++

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

g++ main.cpp add.cpp -o main

(где main.cpp и add.cpp — это имена файлов с кодом, а main — это имя файла-результата)

Пример многофайловой программы


Рассмотрим следующую программу, которая состоит из двух файлов.

add.cpp:

main.cpp:

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

add: идентификатор не найден

При компиляции кода, компилятор не знает о существовании функций, которые находятся в других файлах. Это сделано специально, дабы функции и переменные с одинаковыми именами, но в разных файлах, не вызывали конфликт имён.

Тем не менее, в данном случае, мы хотим, чтобы main.cpp знал (и использовал) функцию аdd(), которая находится в add.cpp. Для предоставления доступа main.cpp к функциям add.cpp, нам нужно использовать предварительное объявление:

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

Что-то пошло не так!

Есть много вещей, которые могут пойти не так, особенно, если вы это делаете в первый раз. Главное — не паниковать:

1. Если вы получили ошибку от компилятора, что функция add() не определена в main(), то, скорее всего, вы забыли записать предварительное объявление функции add() в main.cpp.

2. Если вы получили следующую ошибку от линкера:

unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function _main

то возможных решений есть несколько:

a) Cкорее всего, add.cpp некорректно добавлен в ваш проект. Если вы используете Visual Studio или Code::Blocks, то вы должны увидеть add.cpp в «Обозревателе решений» в списке файлов вашего проекта или в панели проекта IDE. Если добавленного файла нет, то щёлкните правой кнопкой мыши по вашему проекту и добавьте файл, как это показано выше, а затем повторите попытку компиляции вашего проекта.

б) Вполне возможно, что вы добавили add.cpp к другому проекту.

в) Вполне возможно, что добавленный файл не подключен к компиляции/линкингу. Щёлкните правой кнопкой мыши по имени вашего добавленного файла и выберите «Свойства»:

Убедитесь, что пункт «Исключен из сборки» оставлен пустым или выбрано значение «Нет»:

3. Если вы используете Visual Studio с предварительно cкомпилированными заголовочными файлами, то каждый ваш файл должен начинаться со следующей строчки:

Как main.cpp, так и add.cpp.

4. Не пишите следующую строчку в main.cpp:

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

Тест


Разделите следующую программу на два файла (main.cpp и input.cpp): main.cpp должен иметь функцию main(), а input.cpp должен иметь функцию getInteger().

Не забывайте, что для функции getInteger() вам понадобится предварительное объявление в main.cpp.

Ответ

input.cpp:

main.cpp:

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (234 оценок, среднее: 4,78 из 5)
Загрузка...

Комментариев: 30

  1. Аватар Bohdan:

    Срочно нужна помощь.
    Начал программировать на андроид с приложения Dcoder(c++: GCC compiler 6.3 (знаю, что это неудобно и т. д., но лучше так, чем никак).
    С этим уроком получилась зиминка из-за моего не состояния найти способ, как связать несколько файлов именно в этом приложении. Если кто-то что с этим делать, тогда пишите (буду очень благодарен). Автору спасибо за уроки. Всё очень доходчиво написано.

  2. Аватар Дмитрий:

    Большое спасибо автору, читаю уроки — не могу оторваться (давно хотел изучить язык С++).
    У меня такой вопрос: почему при определении (и описании соответственно) функции getInteger() мы оставили скобки пустыми, (ведь мы задействуем 1 переменную и возвращаем ее значение)?

  3. Аватар Андрей:

    Все трудности с ошибками прошел, разобрался, помогли подсказки. Осталось не понятным — '\n', что оно означает?

    1. Аватар Павел:

      Это символ переноса строки, такая управляющая последовательность(и гуглите 🙂 )

  4. Аватар Артем:

    Какая же чудесная находка для меня эти уроки) Автору огромное спасибо за проделанную работу за перевод и адаптацию

    1. Юрий Юрий:

      Пожалуйста 🙂

  5. Аватар Иван:

    Здравствуйте. у меня возникла небольшая заминка. Не могли бы вы помочь мне в её разрешении?
    Я создал оба файла, как объяснялось в задании, добавил add.cpp (Добавить новый элемент —> файл.cpp). И в общем всё работает, но в файле add.cpp возникла ошибка: "IntelliSense: не удаётся открыть источник файл "stdafx.h" ".
    Помогите разобраться.

    1. Юрий Юрий:

      Если у вас Visual Studio 2017, то вам нужно #include <pch.h> вместо stdafx.h.

  6. Аватар Станислав:

    Здравствуйте. Как добавлять файлы в Visual Studio 2017 если он на русском. Просто не очень понятно, переводчик не помогает.

  7. Аватар данила:

    не получается разделить функцию main() на 2 файла (без возвратных функций)…это вообще возможно?)

    1. Аватар Константин:

      Данила, функция это тот же блок, т.е. некий цельный кусок, который из своих недр выдаёт на гора некое одно значение, например — превращает в число результат неких математических вычислений. Это значение можно впихнуть в другой блок, который, используя его произведёт также одно значение, но смысл последнего м.б. другим, например — выведется какая-нибудь надпись. Смыслы закладывает кодер (как и всё остальное). А функцию main() — вообще воспринимай как оглавление книги, в котором записаны вызовы всех функций, которые, собственно, и выполняют поставленные кодером задачи.

  8. Аватар Александр:

    После беглого просмотра десятка-другого уроков понял, что уроки-то неплохие (не считая некоторых грамматических ошибок), да вот возникло стойкое чувство deja vu. И правда, как оказалось, этот курс — просто перевод с минимальными изменениями курса, представленного на сайте LearnCpp.com.
    И хотя я искренне считаю, что людям, не владеющим английским языком, в программировании категорически делать нечего, все же ничего не имею против переводов хороших источников.
    Но только если автор честно пишет, что это не его детище, а просто перевод. Я не смог найти никакого упоминания или ссылки на оригинал. Мало того, вы, Юрий, еще и пытаетесь денег на этом заработать, продавая книжку с этим добром. Если я ошибся, прошу прощения, но если нет, то это очень грустно.

    1. Юрий Юрий:

      А где же, Александр, я писал, что это моё детище? Моё детище — это сайт Ravesli, а уроки С++ — это перевод. На странице "Уроки С++" пролистайте до конца — там источник уроков.

      Насчет денег — да, пытаюсь. Только перевод, а не оригинал, да ещё и с "минимальными изменениями". Уроки по С++ останутся бесплатными на сайте до тех пор, пока я буду поддерживать этот сайт, а всё что дополнительно — то это уже на моё усмотрение.

      1. Аватар Александр:

        Тогда я ошибся, и это чудесно =) Прошу прощения. Я не заметил ссылки, привык их искать где-то в аннотации.

        1. Юрий Юрий:

          Ничего, без проблем 🙂

  9. Аватар Леонид:

    Добрый день! При попытке добавить в функцию, которая находится в отдельном файле, "stdafx.h" компилятор выдаёт ошибку: не удаётся открыть файл включения stdafx.h: No such file or directory. Без stdafx.h всё нормально работает. Visual Studio 2015.

    1. Юрий Юрий:

      Скорее всего у вас отключены предварительно скомпилированные заголовки, коим и является stdafx.h. Работает без него — хорошо, работает с ним — еще лучше.

  10. Аватар Марина:

    Сегодня читала статью с телефона. Очень удобный сайт)

    1. Юрий Юрий:

      Можно и с телефона, и с планшета, и с компьютера, и с ноутбука — лишь бы желание было, а возможность предоставим 🙂

  11. Аватар Илья:

    Когда пишу файл add.cpp постоянно не идёт,это ж линкер мешает по моему???И что ему не так,когда твою программу скопировал,также всё:

    Ошибка LNK2019 ссылка на неразрешенный внешний символ _main в функции "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) add.cpp 1

    1. Юрий Юрий:

      Вы сделали всё как в уроке? Правильно добавили файл? К тому проекту, что нужно?

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

  12. Аватар Максим():

    Почему в VS нужно обязательно подключать библиотеку stdafx.h? Раньше, когда я учился по видеоурокам, я писал программы и без ее подключения. Но конечно есть одно но, я тогда немного изменил параметры создания проекта: поставил галочку на "Empty project" и удалил галочку на "Security Development Lifecycle (SDL) checks ". Может быть это как-то повлияло?

    1. Юрий Юрий:

      stdafx.h — это реализация механизма «предварительно скомпилированных заголовков», который используется для ускорения процесса сборки проектов. В этом файле содержатся вызовы других библиотек и заголовочных файлов, которые нужны для корректного выполнения ваших программ. Т.е. чтобы не прописывать дополнительно подключение определенных библиотек и заголовочных файлов — эти вызовы записали в одном файле и подключают только stdafx.h (1 строчка кода), а не прописывают дополнительно 20 строчек #include. Но от этого можно увидеть толк и почувствовать реальную пользу, когда ваши проекты состоят минимум из десятка файлов.

      Вы можете отключить использование предварительно скомпилированных заголовков в Visual-е в настройках и тогда вам не нужно будет прописывать в каждом файле строчку с подключением stdafx.h. Если вы будете писать простенькие программы на один-два файла, то вам что с stdafx.h, что без него — разница небольшая. Если же будете писать сложные проекты с десятками файлов, то отключив использование stdafx.h, вам придется вручную дополнительно прописывать в каждом файле подключение требуемой библиотеки или заголовочного файла, вызовы которых до этого находились в файле stdafx.h.

      Отключается stdafx.h в Visual Studio так: Project (Проект) -> Properties (Свойства) -> C/C++ -> Precompiled Headers (Предварительно скомпилированные заголовки) и выбираете пункт «Not using Precompiled Files» (сокр. «Не использовать»).

      По поводу того, как повлияли галочки возле «Empty Project» и «Security Development Lifecycle checks» на отключение механизма «предварительно скомпилированных заголовков» я ничего не могу сказать.

  13. Аватар Андрей Оганесян:

    Зачем писать названия в VS (например Source Files) на английском, если в VS есть русский язык?

    1. Юрий Юрий:

      Это уже дело вкуса, кому как привычнее.

      1. Аватар Андрей Оганесян:

        Я имел в виду, что кому то может быть непонятно что значит то или иное название. Мне,как новичку, например, пришлось прибегнуть к гугл-переводчику, чтобы узнать какие это файлы source

        1. Юрий Юрий:

          Хотите вы этого или нет, но английский, даже самый базовый, знать вам придется. Любые команды, ключевые слова и прочее в коде — это обычные английские слова, которые имеют определенные значения. Писать транслитом (русские слова английской раскладкой) названия файлов, переменных, функций, классов — это, как минимум, некрасиво и неудобно. Что тут делать? Учить английский.

        2. Аватар Данила:

          +)).. тоже в гугл лез)))

      2. Аватар Андрей Оганесян:

        Согласен, спасибо

        1. Юрий Юрий:

          Понимаю, полным новичкам могут быть непонятны некоторые слова, но от этого никуда не деться. Там, где можно упростить — я упрощаю, что можно перевести — я перевожу, но всё перевести нельзя. Сам синтаксис любого языка программирования — это английский. И тут уже нужно подстраиваться.

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *