С++: Прототипы функций
В этом уроке мы познакомимся с прототипами функций. Также узнаем, как их определять и для чего они нужны.
Определение прототипа.
Посмотрим на код:
#include <iostream>
#include <string>
int main() {
std::cout << GetAbsolutePath("main.cpp", "andrey") << std::endl;
}
std::string GetAbsolutePath(std::string file_name, std::string user_name) {
return "/home/" + user_name + "/" + file_name;
}На первый взгляд программа написана правильно, но при компиляции мы получим ошибку ./main.cpp:5:20: error: use of undeclared identifier GetAbsolutePath.
Причина, по которой эта программа не компилируется, — компилятор последовательно компилирует содержимое исходных файлов. Когда компилятор достигает вызова функции GetAbsolutePath в функции main, он не знает, что такое GetAbsolutePath, потому что мы определили GetAbsolutePath ниже ее вызова.
Теперь посмотрим на такой пример:
#include <iostream>
#include <string>
// прототип
std::string GetAbsolutePath(std::string, std::string);
int main() {
std::cout << GetAbsolutePath("main.cpp", "andrey") << std::endl;
}
// определение
std::string GetAbsolutePath(std::string file_name, std::string user_name) {
return "/home/" + user_name + "/" + file_name;
}Здесь мы определили прототип функции в верхней части. Теперь программа скомпилируется и будет работать.
Синтаксис прототипов довольно простой и похож на синтаксис определения функций: <ТИП ВОЗВРАЩАЕМОГО ЗНАЧЕНИЯ> <ИМЯ> <КОЛИЧЕСТВО И ТИП АРГУМЕНТОВ>. Поскольку прототип функции является оператором, он должен завершаться точкой с запятой.
Прототип функции не требует предоставления имен переменных-параметров, достаточно списка типов.
Зачем нужны прототипы.
Прототип описывает интерфейс функции для компилятора. Это значит, что он сообщает компилятору, каков тип возвращаемого значения, а также количество и тип аргументов функции.
В нашем случае прототип сообщает компилятору, что функция GetAbsolutePath возвращает значение типа std::string и принимает два аргумента такого же типа. Если программа не предоставит эти аргументы, то прототип позволит компилятору перехватить такую ошибку.
Прототипирование функций позволяет разбивать программу на множество модулей, которые компилируются независимо друг от друга и потом собираются вместе. В этом случае компилятор может вообще не иметь доступа к коду функции во время компиляции main(). То же самое справедливо и в ситуации, когда функция является частью библиотеки.
Прототипы значительно снижают вероятность допущения ошибок. Например, в языке С нет прототипов, и если функция ожидает тип int, а мы передадим в нее double, то могут возникать странные ошибки — потеря точности числа. В C++ же это удастся отловить на этапе компиляции.
Итак, в этом уроке мы познакомились с прототипами функций и узнали, чем они полезны.
Задание
Определите прототип функции GetLength, которая принимает строку и возвращает ее длину.
Полезное
С++: Прототипы функций
В этом уроке мы познакомимся с прототипами функций. Также узнаем, как их определять и для чего они нужны.
Определение прототипа.
Посмотрим на код:
#include <iostream>
#include <string>
int main() {
std::cout << GetAbsolutePath("main.cpp", "andrey") << std::endl;
}
std::string GetAbsolutePath(std::string file_name, std::string user_name) {
return "/home/" + user_name + "/" + file_name;
}На первый взгляд программа написана правильно, но при компиляции мы получим ошибку ./main.cpp:5:20: error: use of undeclared identifier GetAbsolutePath.
Причина, по которой эта программа не компилируется, — компилятор последовательно компилирует содержимое исходных файлов. Когда компилятор достигает вызова функции GetAbsolutePath в функции main, он не знает, что такое GetAbsolutePath, потому что мы определили GetAbsolutePath ниже ее вызова.
Теперь посмотрим на такой пример:
#include <iostream>
#include <string>
// прототип
std::string GetAbsolutePath(std::string, std::string);
int main() {
std::cout << GetAbsolutePath("main.cpp", "andrey") << std::endl;
}
// определение
std::string GetAbsolutePath(std::string file_name, std::string user_name) {
return "/home/" + user_name + "/" + file_name;
}Здесь мы определили прототип функции в верхней части. Теперь программа скомпилируется и будет работать.
Синтаксис прототипов довольно простой и похож на синтаксис определения функций: <ТИП ВОЗВРАЩАЕМОГО ЗНАЧЕНИЯ> <ИМЯ> <КОЛИЧЕСТВО И ТИП АРГУМЕНТОВ>. Поскольку прототип функции является оператором, он должен завершаться точкой с запятой.
Прототип функции не требует предоставления имен переменных-параметров, достаточно списка типов.
Зачем нужны прототипы.
Прототип описывает интерфейс функции для компилятора. Это значит, что он сообщает компилятору, каков тип возвращаемого значения, а также количество и тип аргументов функции.
В нашем случае прототип сообщает компилятору, что функция GetAbsolutePath возвращает значение типа std::string и принимает два аргумента такого же типа. Если программа не предоставит эти аргументы, то прототип позволит компилятору перехватить такую ошибку.
Прототипирование функций позволяет разбивать программу на множество модулей, которые компилируются независимо друг от друга и потом собираются вместе. В этом случае компилятор может вообще не иметь доступа к коду функции во время компиляции main(). То же самое справедливо и в ситуации, когда функция является частью библиотеки.
Прототипы значительно снижают вероятность допущения ошибок. Например, в языке С нет прототипов, и если функция ожидает тип int, а мы передадим в нее double, то могут возникать странные ошибки — потеря точности числа. В C++ же это удастся отловить на этапе компиляции.
Итак, в этом уроке мы познакомились с прототипами функций и узнали, чем они полезны.
Задание
Определите прототип функции GetLength, которая принимает строку и возвращает ее длину.
Полезное
Ваше упражнение проверяется по этим тестам
#include "test_helper.h"
TEST_CASE("testing prototipe function") {
std::string expected = "11\n";
std::string actual = get_output(sizeof(expected));
CHECK(actual == expected);
}Решение учителя откроется через:
20:00
