8.9 – Введение в перегрузку функций

Добавлено 14 июня 2021 в 07:14
Последнее редактирование 24 июня 2021 в 18:24

Рассмотрим следующую функцию:

int add(int x, int y)
{
    return x + y;
}

Эта тривиальная функция складывает два числа int и возвращает результат int. Однако что, если нам также нужна функция, которая может складывать два числа с плавающей запятой? Эта функция add() не подходит, поскольку любые параметры с плавающей запятой будут преобразованы в целые числа, что приведет к потере дробных частей аргументов с плавающей запятой.

Один из способов обойти эту проблему – определить несколько функций с немного разными именами:

int addInteger(int x, int y)
{
    return x + y;
}
 
double addDouble(double x, double y)
{
    return x + y;
}

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

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

Знакомство с перегрузкой функций

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

Чтобы перегрузить нашу функцию add(), мы можем просто определить другую функцию add(), которая принимает параметры double:

double add(double x, double y)
{
    return x + y;
}

Теперь у нас есть две версии add() в одной области видимости:

int add(int x, int y) // целочисленная версия
{
    return x + y;
}
 
double add(double x, double y) // версия с плавающей запятой
{
    return x + y;
}
 
int main()
{
    return 0;
}

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

Ключевые выводы


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

Связанный контент


Поскольку операторы в C++ – это просто функции, они также могут быть перегружены. Мы обсудим это в разделе «13.1 – Введение в перегрузку операторов».

Введение в разрешение перегрузки

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

Вот простой пример, демонстрирующий это:

#include <iostream>
 
int add(int x, int y)
{
    return x + y;
}
 
double add(double x, double y)
{
    return x + y;
}
 
int main()
{
    std::cout << add(1, 2);     // вызывает add(int, int)
    std::cout << '\n';
    std::cout << add(1.2, 3.4); // вызывает add(double, double)
 
    return 0;
}

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

3
4.6

Когда мы предоставляем целочисленные аргументы в вызове add(1, 2), компилятор определит, что мы пытаемся вызвать add(int, int). А когда мы предоставляем аргументы с плавающей запятой в вызове add(1.2, 3.4), компилятор определит, что мы пытаемся вызвать add(double, double).

Выполнение компиляции

Чтобы программа могла компилировать перегруженные функции, должны выполняться две вещи:

  1. Каждую перегруженную функцию нужно отличать от других. Мы обсудим, как можно различать функции в уроке «8.10 – Различение перегруженных функций».
  2. Каждый вызов перегруженной функции должен решаться в перегруженную функцию. Мы обсудим, как компилятор сопоставляет вызовы функций с перегруженными функциями в уроке «8.11 – Разрешение перегрузки функций и неоднозначные совпадения».

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

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

Заключение

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

Лучшая практика


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

Лучшая практика


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

Теги

C++ / CppLearnCppДля начинающихОбучениеПерегрузка (программирование)Программирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.


  • 2023-02-05Сергей

    Опечатка: в конце урока два одинаковых блока "Лучшей практики"