1. Структура программы на языках С и С++.

Функции С и С++. Перегрузка функций в С++. Ссылки.

Что такое программа на Си

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

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

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

Компиляция программы

Объявления необходимы компилятору. Объявлять можно один раз, определять - сколько угодно. Компилятор подставляет константы.

В С и С++ каждый файл компилируется раздельно, либо с помощью makefile.

Получение исполняемого файла *.exe:

image
  1. Препроцессирование - удаление комментариев, замена #define, подключение заголовочных файлов *.h (путем копирования содержимого). Для избежания повторного копирования используется #pragma once или #ifndef G_H.

  2. Компиляция - перевод написанного на языке C++ кода в код ассемблера.

  3. Ассемблирование - перевод из кода ассемблера в машинный код. Получаем объектный файл с расширением *.obj.

  4. Компоновка/линковка - объединение объектных файлов в один исполняемый *.exe.

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

#pragma once исключает множественное включение файлов.

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

Заголовочные файлы - описание типов, констант, библиотеки, функций, логически вынесенных в другой исходный файл.

Что можно, а что нельзя определять в заголовочном файле:

  • Определять переменные нельзя. Мы конечно можем это сделать, и на этапе компиляции проблем не будет, но сборщик покажет множественное определение - ошибочка.

  • То же самое касается функций. В заголовочном файле описываются только прототипы функций.

  • К языковой константе компилятор относится как к макросу, поэтому в заголовочном можно определять константу.

  • Аналогично с типами - типы тоже можно определять в заголовочном файле.

То есть все константы и типы выносим в заголовочный, а так же прототипы функций.

С такими константами компилятор вычисляет ее, и подставляет в код вместо вызова.

const int a = 100; \\ Константа времени компиляции
------------------
int i;
...
const int a = i; \\ Константа времени выполнения и является полноценным данным

Определяем константы в том случае, если она вычислима на этапе компиляции - Константа времени компиляции, а те константы которые не могут быть вычислены на этапе компиляции, а вычисляются во время выполнения, то это Константа времени выполнения нельзя определять в заголовочном файле

В языке С структурное соответствие типов, то есть typedef это определение еще одного имени, один и тот же тип может иметь много имен, проверяется не имя типа, а его структура.

В языки С++ именное соответствие типов, две одинаковые структуры, имеющие разные имена являются разными типами.

Подключать g.h на уровне f.h файлов нельзя, приводит к лавинное перекомпиляции, на время разработки мы их комментируем. В случае релиз версии тогда, все g.h включения идут в f.h файл, а в f.cpp .h комментируем.

image

f.h и f.cpp рассматривается как модуль и многие среды создают такие пары.

Ссылки

Структуру по значению передавать плохо, так как происходит копирование в стек, а это занимает время. Лучше по ссылке или указателю. Но у указателей есть проблема - контроль (сложно проверить корректность, только на NULL).

Ссылка (alias) - ещё одно имя того же самого данного. Ссылка - не тип данных!

// Пример, демонстрирующий принцип работы ссылки
int i;
int& ai = i;
ai = 2;       // аналогично, что i = 2;

Ссылки используются для передачи параметра в функцию. На низком уровне ссылки хоть ничем не отличается от указателя, но идет контроль!

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

\\ передача по ссылке
void swap(double &d1, doueble &d2) \\ под капотом это тот же указатель, но с контролем
{
   doueble temp = d1;
   d1 = d2;
   d2 = temp;
}
...
swap(arr[i], arr[j]);
...

\\ возврат по ссылке

\\ такого нельзя
double &maxElem(double *arr, int count)
{
   double amax = arr;
   for(double *p = arr + 1; p < count; p++)
      if(amax < *p)
        amax = *p
   return amax \\ возврат ссылки на локальную переменную
}
\\ о звездочках или указателей забыть
double &maxElem(double *arr, int count)
{
   double *pmax = arr;
   for(double *p = arr + 1; p < count; p++)
      if(*pmax < *p)
        *p = max
   return *pmax \\ возврат ссылку на этот элемент, формировать левые выражения, нахождения по отношению оператора =
}
...
maxElem(arr, n) = 0; \\ обнулил первый максимальный элемент
...

Перегрузка функций

В С++ можно создавать разные функции с одинаковыми именами, у которых параметры разного типа или их разное количество - использовать перегрузку функций.

Теряется такой механизм неявное приведение типа - а это ХОРОШО

В С++ о неявном будем говорит, так как создатель добавил возможность задавать свои механизмы неявного типа - но это ПЛОХО, пишем код для врагов.

На перегрузку функции влияет:

  • Разное количество принимаемых параметров.

  • Разный тип переменных.

  • const значение функции/метода. Если объект константный, то будет вызываться const метод, иначе не const.

Примечание о том, что значит модификатор const у метода. Константный метод - это метод, который гарантирует, что не будет изменять объект или вызывать неконстантные методы класса (поскольку они могут изменить объект). Соответственно, для константных объектов нельзя вызывать неконстантные методы.

Тип возвращаемой переменной не имеет значение.

//  Пример функции возведения в квадрат
int sqr(int x);  // для целых
double sqr(double x); // для дробных
int sqr(const int x) const; // для const  целых

Last updated