Структура кода на С++


Разбиение программы на файлы

Зачем разбивать программу на файлы?
  • С небольшими файлами удобнее работать.
  • Разбиение на файлы структурирует код, отделяя одно подсистему от другой. 
  • Позволяет нескольким программистам разрабатывать приложение одновременно.
  • Ускорение повторной компиляции при небольших изменениях в отдельных частях программы.
Файлы с кодом на C++ бывают двух типов:
  1. файлы с исходным кодом (расширение .cpp, иногда .C);
  2. заголовочные файлы (расширение .hpp или .h).

Расширения файлов С++

Кроме вышеуказанных, в C++ также используются следующие расширения:
  • .cxx, .cc — для файлов с исходным кодом;
  • .hxx, .hh — для заголовочных файлов.
Интересно отметить, что файлы стандартной библиотеки C++ не используют расширение вовсе, например:
  • iostream;
  • algorithm;
  • vector.
Разделение на файлы с исходным кодом и заголовочные файлы чисто условное, нет правил, запрещающих использовать .cpp файл как заголовочный, однако мы не рекомендуем так делать — использование общепринятых правил именования файлов упростит жизнь вам и вашим коллегам.

Не стоит помещать определения в заголовочные файлы без явной необходимости. В C++ есть способы, позволяющие поместить определение в заголовочный файл, не вызвав при этом ошибки компоновщика, но, как правило, это приводит к увеличению объектного файла и программы в целом.

Объявления и определения

Объявление (declaration) — вводит имя, возможно, не определяя деталей. Например, ниже перечислены объявления:
  • int a; — объявление переменной типа int,
  • void foo(); — объявление функции с именем foo,
  • void bar() { foo(); } — объявление функции с именем bar.
Определение (definition) — это объявление, дополнительно определяющее детали, необходимые компилятору. Из перечисленных выше объявлений, определениями являются только два:
  • int a; — объявление переменной типа int,
  • void bar() { foo(); } — объявление функции вместе с телом является определением.
Для определения переменной достаточно указать ее тип, а для определения функций, кроме имени, типов параметров и возвращаемого значения, нужно указать еще тело функции. Проще говоря, определение содержит всю информацию, необходимую компилятору, чтобы выделить память для хранения объекта.

В C++ есть также возможность объявить переменную, не определяя ее:
extern int a;

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

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

В файлы для кода кладутся определения. В заголовочные файлы нужно класть объявления. Соответственно если есть какая-то функция, её определение пишется внутрь файла с кодом (т.е. внутрь .cpp файла), а если нужно использовать данную функцию за пределами этого файла, то её объявление добавляется в некоторый .hpp файл, который включается в каждый файл в котором нужно эту функцию вызывать.

Заголовочные файлы

Компиляция следующих двух файлов выдаст ошибку:
Файл foo.cpp:
// определение (definition) функции foo
void foo()
{
 bar();
}
Файл bar.cpp:
// определение (definition) функции bar
void bar() { }
Т.к. это два разных файла, то их компиляция будет проходить по отдельности. И когда компилятор будет читать файл foo.cpp, то встретив вызов функции bar, он не будет знать, что это функция определена в каком-то другом файла.


Для того чтобы это исправить нужно добавить в файл foo.cpp объявление функции bar:
Файл foo.cpp:
// объявление (declaration) функции bar
void bar();

// определение (definition) функции foo
void foo()
{
 bar();
}
Файл bar.cpp:
// определение (definition) функции bar
void bar() { }


Предположим, что мы изменили функцию bar. Следующий код некорректен — объявление отличается от определения. Данный код скомпилируется, но его поведение неопределенно.
Файл foo.cpp:
void bar();

void foo()
{
 bar();
}
Файл bar.cpp:
int bar () { return 1; }


Предположим, что функция bar используется не в одном файле, а в нескольких, тогда придётся исправлять объявления функции bar в этих файлах, в каждом по отдельности. Для того чтобы локализовать изменения используются заголовочные файлы. В заголовочный файл выносится объявление функции и во всех местах, где функция используется, просто подключается соответствующий заголовочный файл.
Файл foo.cpp:
#include "bar.hpp"

void foo()
{
 bar();
}
Файл bar.cpp:
int bar() { return 1; }
Добавим заголовочный файл bar.hpp:
int bar();


Может случиться двойное включение заголовочного файла.
Файл foo.cpp:
#include "foo.hpp"
#include "bar.hpp"

void foo()
{
 bar();
}
Файл foo.hpp:
#include "bar.hpp"

void foo();


Это можно исправить двумя способами:
1) Наиболее переносимо через "стражи включения". Файл bar.hpp:
#ifndef BAR_HPP
#define BAR_HPP

int bar();
#endif
2) Наиболее просто. Файл bar.hpp:
#pragma once

int bar();


Например, есть проект, в котором есть три файла с различными определениями: utility.cpp, lexer.cpp и parser.cpp. Каждому файлу соответствует заголовочный файл с необходимыми объявлениями: utility.hpp, lexer.hpp и parser.hpp. Каждый из файлов определений непосредственно (т. е. с помощью директивы include) подключает соответствующий ему заголовочный файл с объявлениями (т. е. utility.cpp подключает utility.hpp, а lexer.cpp подключает lexer.hpp и аналогично для parser.cpp и parser.hpp). Кроме того, файл parser.hpp непосредственно подключает заголовки lexer.hpp и utility.hpp, а файл lexer.hpp подключает заголовок utility.hpp.


  • Файл parser.cpp включает заголовочный файл utility.hpp.
  • Если в заголовке utility.hpp отсутствует защита от повторного включения, то он будет включен в parser.cpp дважды.
  • Файл utility.cpp подключает только один заголовочный файл из перечисленных.


Примеры объявлений, которые не стоит помещать в заголовочные файлы:
  • void bar() { foo(); }
  • int a;
  • void foo() { std::cout << "Hello, World!\n"; }

1 комментарий:

  1. Консоли от корпорации Microsoft не сразу завоевали всемирную известность и доверие игроков. 1-ая консоль под названием Xbox, вышедшая в далеком 2001 году, существенно уступала PlayStation 2 по количеству проданных приставок. Но все изменилось с выходом Xbox 360 - консоли седьмого поколения, которая стала по-настоящему "народной" для жителей России и государств СНГ - http://ru-xbox.ru/load/1/1/1. Веб-сайт Ru-Xbox.Ru является популярным ресурсом среди поклонников приставки, так как он предлагает игры для Xbox 360, которые поддерживают все существующие версии прошивок - совершенно бесплатно! Зачем играть на оригинальном железе, если имеется эмуляторы? Для Xbox 360 игры выходили долгое время и находятся как посредственными проектами, так и хитами, многие из которых даже сейчас остаются эксклюзивными для это консоли. Некие пользователи, желающие сыграть в игры для Xbox 360, смогут задать вопрос: зачем нужны игры для прошитых Xbox 360 freeboot или различными версиями LT, в случае если имеется эмулятор? Рабочий эмулятор Xbox 360 хоть и существует, однако он просит производительного ПК, для покупки которого потребуется вложить существенную сумму. К тому же, всевозможные артефакты в виде исчезающих текстур, недостатка некоторых графических эффектов и освещения - смогут изрядно попортить впечатления об игре и отбить желание для ее предстоящего прохождения. Что предлагает этот веб-сайт? Наш портал на сто процентов посвящен играм для приставки Xbox 360. У нас вы можете совершенно бесплатно и без регистрации скачать игры на Xbox 360 через торрент для следующих версий прошивок консоли: - FreeBoot; - LT 3.0; - LT 2.0; - LT 1.9. Каждая прошивка имеет свои особенности обхода интегрированной защиты. Потому, для запуска той или другой игры потребуется загрузить специальную ее версию, которая полностью адаптирована под одну из четырех вышеперечисленных прошивок. На нашем веб-сайте вы можете без труда получить желаемый проект под нужную прошивку, так как возле каждой игры находится название версии (FreeBoot, LT 3.0/2.0/1.9), под которую она адаптирована. Пользователям данного ресурса доступна особая категория игр для 360-го, созданных для Kinect - специального дополнения, которое считывает все движения 1-го или нескольких игроков, и позволяет управлять с помощью их компьютерными персонажами. Большой выбор ПО Не считая способности скачать игры на Xbox 360 Freeboot либо LT разных версий, здесь можно подобрать программное обеспечение для консоли от Майкрософт: - современные версии Dashboard, которые позволяют кастомизировать интерфейс консоли под свои нужды, сделав его более комфортным и нынешним; - браузеры; - просмотрщики файлов; - сохранения для игр; - темы для консоли; - программы, для конвертации образов и записи их на диск. Помимо перечисленного выше игры на Xbox 360 Freeboot можно запускать не с дисковых, а с USB и прочих носителей, используя программу x360key, которую вы можете достать на нашем сайте. Посетителям доступно огромное количество нужных статей, а кроме этого форум, где можно пообщаться с единомышленниками либо попросить совета у более опытнейших хозяев консоли.

    ОтветитьУдалить