Бесплатный курс по C++. Зарегистрируйтесь для отслеживания прогресса →

C++: Аргументы по умолчанию

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

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

Посмотрим на следующий код:

#include <string>
#include <fstream> // библиотека для работы с файлами

void CreateConfigFile(std::string file_path = "/usr/local/nginx/conf") {
  std::ofstream Config(file_path); // создаем конфигурационный фаил
  Config.close(); // и тут же закрываем его 
}

У нас есть функция, которая создает пустой конфигурационный файл для сервера. Если вызывающая сторона не передаст в функцию путь, то будет использован путь по умолчанию /usr/local/nginx/conf.

Несколько аргументов по умолчанию

Функция может иметь несколько параметров с аргументами по умолчанию:

#include <string>
#include <iostream>
#include <fstream> 

void CreateConfigFile(std::string file_path = "/usr/local/nginx/conf", int port = 80, std::string protocol = "https") {
  std::ofstream Config(file_path);
  Config << port << std::endl;
  Config << protocol;
  Config.close(); 
}

Если вызвать функцию CreateConfigFile() без аргументов, то будет создан конфигурационный файл по пути /usr/local/nginx/conf и в него будет записан номер порта 80, протокол https.

Обратите внимание, что невозможно предоставить аргумент для параметра protocol без предоставления аргументов для параметров file_path и port. Это связано с тем, что C++ не поддерживает синтаксис вызова функции, такой как CreateConfigFile( , ,"http"). Это имеет два основных последствия:

  • Все аргументы по умолчанию должны быть для крайних правых параметров. Запрещено следующее:
void CreateConfigFile(std::string file_path, int port, std::string protocol = "https")
  • Если существует более одного аргумента по умолчанию, крайний левый аргумент по умолчанию должен быть тем, который с наибольшей вероятностью будет явно установлен пользователем.

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

Такой код вызовит ошибку:

void CreateConfigFile(std::string file_path = "/usr/local/nginx/conf", int port = 80, std::string protocol = "https")

void CreateConfigFile(std::string file_path = "/usr/local/nginx/conf", int port = 80, std::string protocol = "https") {
  std::ofstream Config(file_path);
  Config << port << std::endl;
  Config << protocol;
  Config.close(); 
}

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

Аргументы по умолчанию и перегрузка функций

Функции с аргументами по умолчанию могут быть перегружены. Например, разрешено следующее:

void CreateConfigFile(std::string file_path, int port);
void CreateConfigFile(std::string file_path, std::string port = "80");

Теперь если вызвать функцию CreateConfigFile("/usr/local/nginx/conf"), то в конфигурационный файл будет записано значение порта 80.

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

void CreateConfigFile(std::string file_path);
void CreateConfigFile(std::string file_path, std::string port = "80");

Компилятор не сможет разрешить эту перегрузку, потому что при вызове функции CreateConfigFile() возникнет неоднозначность.

Аргументы по умолчанию предоставляют полезный механизм для указания параметров, для которых пользователю необязательно указывать значения.

Задание

Напишите функцию GetHiddenCard(), которая принимает в качестве первого параметра номер кредитной карты(16 символов) в виде строки и возвращает его скрытую версию. Если исходная карта имела номер 2034399002125581, то скрытая версия выглядит так ****5581. Другими словами, функция заменяет первые 12 символов, на звездочки. Количество звездочек регулируется вторым необязательным параметром. Значение по умолчанию — 4.

GetHiddenCard("2034399002121100", 1); // "*1100"
GetHiddenCard("1234567812345678", 2); // "**5678"
GetHiddenCard("1234567812345678", 3); // "***5678"
GetHiddenCard("1234567812345678");    // "****5678"

Для извлечения подстроки воспользуйтесь методом substr():

int main() { 
  std::string str = "2034399002121100";

  std::cout << str.substr(str.length() - 4, 4); // 1100
}

Для повторения строки указанное количество раз воспользуйтесь std::string:

int main() { 
  std::cout << std::string(4, '*') // ****
}
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

  • Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨

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

Мой код отличается от решения учителя 🤔

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

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

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Полезное


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе