Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по 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, вы используете одно осмысленное имя и позволяете компилятору позаботиться об остальном.

challenge icon

Задание

Легко

Давайте создадим класс для форматирования сообщений, который продемонстрирует возможности перегрузки функций. Вы создадите класс 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: Считайте четыре входных значения (каждое на отдельной строке):
    1. Простой текст сообщения
    2. Уровень приоритета (целое число)
    3. Временная метка (число с плавающей точкой)
    4. Имя отправителя

    Создайте объект 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;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование