Перевантаження функцій. Перевантаження функцій у класах. Перевантаження конструкторів класу. Доступ до перевантаженої функції за покажчиком. Приклади

Перевантаження функцій. Перевантаження функцій у класах. Перевантаження конструкторів класу. Доступ до перевантаженої функції за покажчиком. Приклади


Зміст


1. Які функції називаються “перевантаженими”? Що означає термін “перевантаження”?

“Перевантаження” функції – це оголошення функції з тим же іменем декілька разів. Таким чином, в деякій області видимості ім’я “перевантажена” функція оголошується декілька разів. Щоб компілятор міг відрізняти “перевантажені” функції, ці функції повинні відрізнятися між собою списком вхідних параметрів.

В загальному випадку оголошення перевантаженої функції в деякій області видимості виглядає наступним чином:

return_type1 FunName(parameters_list_1)
{
    // ...
}

return_type2 FunName(parameters_list_2)
{
    // ...
}

return_typeN FunName(parameters_list_N)
{
    // ...
}

де

  • FunName – ім’я перевантаженої функції;
  • parameters_list1, parameters_list2, …, parameters_listN – списки параметрів “перевантаженої” функції з іменем FunName;
  • return_type1, return_type2, …, return_typeN – типи параметрів, що повертаються “перевантаженою” функцією FunName. Компілятор розрізняє “перевантажені” функції тільки за списком отриманих параметрів але не за повернутим значенням.

2. За якими ознаками відрізняються перевантажені функції? Приклад

Перевантажені функції відрізняються за списком параметрів. Списки параметрів перевантажених функцій мають відрізнятися за такими ознаками:

  • кількістю параметрів;
  • якщо кількість параметрів однакова, то типами параметрів.

Наприклад. Функція Max() перевантажена і відрізняється кількістю параметрів та типами параметрів.

// функція Max з двома параметрами типу int
int Max(int a, int b)
{
    // ...
}

// функція Max з трьома параметрами типу int
int Max(int a, int b, int c)
{
    // ...
}

// функція Max з двома параметрами типу double
int Max(double a, double b)
{
    // ...
}

3. Приклади перевантаження функцій

Приклад 1. Функція Equal(), яка порівнює два значення різних типів. Функція має три перевантажені реалізації для різних типів (char, int, double).

Програмний код, що демонструє використання функції Equal() наступний:

#include "stdafx.h"
#include <iostream>
using namespace std;

bool Equal(char c1, char c2)
{
    return (bool)(c1==c2);
}

bool Equal(double d1, double d2)
{
    return (bool)(d1==d2);
}

bool Equal(int i1, int i2)
{
    return (bool)(i1==i2);
}

int _tmain(int argc, _TCHAR* argv[])
{
    bool b;
    b = Equal(5,6); // викликається Equal(int, int), b = 0
    b = Equal(3.755, 3.755); // викликається Equal(double, double), b = 1
    b = Equal('A', 'A'); // викликається Equal(char, char), b = 1
    return 0;
}

Приклад 2. Функція Average(), яка знаходить середнє арифметичне. Функція має 4 перевантажені реалізації для різної кількості цілочисельних параметрів.

Програмний код, що демонструє застосування функції наступний:

#include "stdafx.h"
#include <iostream>
using namespace std;

double Average(int a, int b)
{
    return (a+b)/2.0;
}

double Average(int a, int b, int c)
{
    return (a+b+c)/3.0;
}

double Average(int a, int b, int c, int d)
{
    return (a+b+c+d)/4.0;
}

double Average(int a, int b, int c, int d, int e)
{
    return (a+b+c+d+e)/5.0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    double avg;
    avg = Average(2,3); // avg = 2.5
    avg = Average(2,3,5); // avg = 3.3333
    avg = Average(2,3,5,8); // avg = 4.5
    avg = Average(2,3,5,8,11); // avg = 5.8
    return 0;
}
4. Приклад перевантаження функції у класі

Задано клас Day, що реалізує день тижня. У класі перевантажено функцію Set(), що встановлює новий день тижня. Метод Set() має 2 реалізації:

  • без параметрів;
  • з одним параметром.

Програмний код, що демонструє застосування “перевантаження” функцій у класі має наступний вигляд:

#include "stdafx.h"
#include <iostream>
using namespace std;

class Day
{
    int day;

    public:
    // метод Set() перевантажено
    void Set(int nday) { day = nday; }
    void Set(void) { day = 1; }
    int Get(void) { return day; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Day D;
    int day;

    // використання перевантаженого метода Set
    D.Set();
    day = D.Get(); // day = 1

    D.Set(5);
    day = D.Get(); // day = 5

    cout << day << endl;
    return 0;
}

5. Чи можуть вважатись перевантаженими функції, які мають однакові імена, однакову кількість та типи параметрів але які повертають значення різних типів?

Ні. Компілятор розпізнає перевантажені функції тільки за отримуваними параметрами. Якщо дві функції мають однакові імена, однакову кількість та типи параметрів але повертають різні значення, то такі функції вважаються однаковими. У цьому випадку компілятор видасть помилку:

Наприклад. У нижченаведеному коді оголошується дві функції з іменем Inc5():

int Inc5(int d)
{
    return d+5;
}

double Inc5(int d)
{
    return (double)(d+5.0);
}

Як видно, функції повертають значення різних типів. Оскільки, функції мають однакові імена, однакову кількість та типи параметрів, то вищенаведений код видасть помилку компілятора

'double Get5(int)' : overloaded function differs only by return type from 'int Get5(int)'

6. Для чого використовується перевантаження конструкторів класу? Переваги перевантаження конструкторів класу

Перевантаження конструкторів класу дає такі переваги:

  • підвищення гнучкості класу при його створенні. З допомогою перевантаження конструкторів користувач вибирає оптимальний спосіб створення об’єкту. Якщо спробувати створити об’єкт класу способом, для якого непередбачений конструктор, то компілятор видасть повідомлення про помилку;
  • можливість створення ініціалізованих та неініціалізованих об’єктів або об’єктів, що ініціалізовані за замовчуванням. У цьому випадку передбачається 2 варіанти реалізації конструктора: з ініціалізацією та без неї;
  • можливість створення конструкторів копіювання.


7. Приклад перевантаження конструкторів у класі

Приклад. Задано клас Cylinder що реалізує циліндр. У класі перевантажується конструктор, який може викликатись одним з трьох способів:

  • конструктор без параметрів;
  • конструктор з 1 параметром;
  • конструктор з 2 параметрами.
#include "stdafx.h"
#include <iostream>
using namespace std;

class Cylinder
{
    double r, h;

    public:
    // конструктор без параметрів
    Cylinder()
    {
        r = 1;
        h = 1;
    }

    // конструктор з 1 параметром
    Cylinder(double h)
    {
        r = 1.0;
        this->h = h;
    }

    // конструктор з двома параметрами
    Cylinder(double h, double r)
    {
        this->h = h;
        this->r = r;
    }

    // методи доступу
    double GetR(void) { return r; }
    double GetH(void) { return h; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Cylinder cl; // виклик конструктора без параметрів
    Cylinder cl1(5); // виклик конструктора з 1 параметром
    Cylinder cl2(7, 9); // виклик конструктора з 2 параметрами
    double d;

    d = cl.GetH(); // d = 1
    d = cl1.GetH(); // d = 5
    d = cl2.GetH(); // d = 7

    cout << d << endl;
    return 0;
}

8. Яким чином здійснюється доступ до перевантаженої функції з допомогою покажчика на функцію? Приклад

При оголошенні покажчика на “перевантажену” функцію, компілятор визначає потрібну функцію для покажчика за його сигнатурою при оголошенні.

Наприклад. Нехай задано 3 “перевантажені” функції Increment() для типів int, double, char. При оголошенні покажчика на функцію, потрібно явно задати тип покажчика при оголошенні.

Нижченаведений код демонструє використання покажчика на перевантажену функцію

#include "stdafx.h"
#include <iostream>
using namespace std;

int Increment(int i)
{
    return i+1;
}

double Increment(double d)
{
    return d+1;
}

char Increment(char c)
{
    return c+1;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int (*pi)(int); // покажчик на функцію, яка отримує параметром int і повертає int
    pi = Increment; // p вказує на int Increment(int)
    int d = (*pi)(4); // d = 5

    char (*pc)(char);
    pc = Increment; // p вказує на char Increment(char)
    char c = (*pc)('F'); // c = 'G'

    cout << c << endl;
    return 0;
}

9. Для чого використовується ключове слово overload?

Ключове слово overload використовувалось у ранніх версіях C++ для вказання того, що функція є перевантаженою. Загальна форма оголошення “перевантаженої” функції з використання ключового слова overload має вигляд:

overload ім’я_функції;

Наприклад. Якщо перевантажена функція Max() що знаходить максимум між множиною чисел, то рядок

overload Max;

сповіщає компілятор про те, що функція Max() є перевантаженою.


Зв’язані теми