Перегрузка функций
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 57 из 104.
Перегрузка функций позволяет определять несколько функций с одним и тем же именем, но разными списками параметров. Компилятор выбирает правильную версию на основе передаваемых вами аргументов. Это ключевая форма полиморфизма времени компиляции.
Чтобы перегрузка работала, функции должны различаться своей сигнатурой — количеством параметров, их типами или и тем, и другим:
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
};
Calculator calc;
calc.add(5, 3); // Вызывает add(int, int)
calc.add(2.5, 3.7); // Вызывает add(double, double)
calc.add(1, 2, 3); // Вызывает add(int, int, int)Компилятор проверяет каждый вызов и сопоставляет его с соответствующей перегрузкой. Это происходит полностью на этапе компиляции, поэтому накладные расходы во время выполнения отсутствуют.
Важно: Один лишь тип возвращаемого значения не позволяет различать перегруженные функции. Следующий код вызовет ошибку компиляции:
int getValue();
double getValue(); // Ошибка: нельзя перегружать только по типу возвращаемого значенияПерегрузка функций делает ваш код более интуитивно понятным. Вместо того чтобы создавать отдельные имена, такие как addInts, addDoubles и addThreeInts, вы используете одно осмысленное имя и позволяете компилятору позаботиться об остальном.
Задание
ЛегкоДавайте создадим класс для форматирования сообщений, который продемонстрирует возможности перегрузки функций. Вы создадите класс Formatter с несколькими методами format(), которые обрабатывают различные типы входных данных, позволяя компилятору выбирать нужную версию в зависимости от того, что вы передаете.
Вы организуете свой код в двух файлах:
Formatter.h: Определите классFormatterс перегруженными методамиformat(), которые обрабатывают различные сценарии:- Метод, который принимает одну строку
std::stringи выводит:Message: <text> - Метод, который принимает
std::stringи уровень приоритетаint, выводя:[Priority <priority>] <text> - Метод, который принимает
std::stringи временную меткуdouble, выводя:[<timestamp>s] <text> - Метод, который принимает три параметра
std::string(отправитель, получатель, сообщение) и выводит:From <sender> to <receiver>: <message>
format()— компилятор выберет правильный на основе аргументов.- Метод, который принимает одну строку
main.cpp: Считайте четыре входных значения (каждое на отдельной строке):- Простой текст сообщения
- Уровень приоритета (целое число)
- Временная метка (число с плавающей точкой)
- Имя отправителя
Создайте объект
Formatterи продемонстрируйте работу всех четырех перегруженных методов:- Вызовите
format()только с текстом сообщения - Вызовите
format()с текстом сообщения и приоритетом - Вызовите
format()с текстом сообщения и временной меткой - Вызовите
format()с отправителем, "Admin" в качестве получателя и текстом сообщения
Например, при входных данных System ready, 3, 12.5 и Server:
Message: System ready
[Priority 3] System ready
[12.5s] System ready
From Server to Admin: System readyОбратите внимание, как вы вызываете один и тот же метод format() четыре раза, но каждый вызов запускает разную версию в зависимости от типов и количества аргументов. Это полиморфизм на этапе компиляции в действии — компилятор определяет, какую перегрузку использовать, еще до запуска программы.
Шпаргалка
Перегрузка функций позволяет определять несколько функций с одним и тем же именем, но разными списками параметров. Компилятор выбирает правильную версию на основе аргументов, переданных во время компиляции.
Функции должны различаться своей сигнатурой — количеством параметров, их типами или и тем, и другим:
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
};
Calculator calc;
calc.add(5, 3); // Вызывает add(int, int)
calc.add(2.5, 3.7); // Вызывает add(double, double)
calc.add(1, 2, 3); // Вызывает add(int, int, int)Важно: Один только тип возвращаемого значения не может служить отличием для перегруженных функций:
int getValue();
double getValue(); // Ошибка: нельзя перегружать только по типу возвращаемого значенияПерегрузка функций — это форма полиморфизма времени компиляции, которая не влечет за собой накладных расходов во время выполнения.
Попробуйте сами
#include <iostream>
#include <string>
#include "Formatter.h"
using namespace std;
int main() {
// Чтение входных данных
string message;
getline(cin, message);
int priority;
cin >> priority;
double timestamp;
cin >> timestamp;
cin.ignore();
string sender;
getline(cin, sender);
// TODO: Создать объект Formatter
// TODO: Вызвать format() только с текстом сообщения
// TODO: Вызвать format() с текстом сообщения и приоритетом
// TODO: Вызвать format() с текстом сообщения и меткой времени
// TODO: Вызвать format() с отправителем, "Admin" в качестве получателя и текстом сообщения
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер