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

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


Зміст


1. В чому полягає суть перевантаження методу у класі?

Мова програмування C# дозволяє здійснювати перевантаження методів у класі. Перевантаження означає використання одного імені для різних методів. Фактично, перевантажується ім’я методу.

Перевантаження методу – це програмна реалізація декількох методів для яких виконуються наступні умови:

  • усі перевантажені методи мають однакове ім’я;
  • перевантажені методи відрізняються параметрами. Точніше кажучи, тип параметрів або кількість параметрів у перевантажених методах повинні відрізнятись

Перевантаження методу в класі – це оголошення іншого методу з таким самим іменем у класі але з відмінними параметрами. Параметри перевантаженого методу повинні відрізнятись типами або кількістю.

Якщо викликається перевантажений метод, то компілятор вибирає той варіант методу, параметри якого співпадають (за типом та за кількістю) з аргументами, що передаються в метод.

 

2. Що таке сигнатура методу? Які вимоги до сигнатури методу з точки зору перевантаження?

Сигнатура методу – це ім’я методу та список його параметрів. З точки зору перевантаження до сигнатури ставиться вимога:

  • в одному класі не повинно існувати двох методів з однаковою сигнатурою.

 

3. Чи вважаються перевантаженими два методи, які мають однакові параметри але повертають різні значення?

Ні. Це є помилка. Згідно синтаксису C# перевантажені методи обов’язково повинні відрізнятись параметрами.

 

4. Приклади перевантажених методів

Приклад 1. У класі MaxMethods оголошується перевантажений метод Max(), який має 3 реалізації. Метод реалізує пошук максимуму між різною кількістю параметрів типу int.

// перевантаження методу Max() у класі MaxMethods
class MaxMethods
{
  // перевантажені методи Max()
  public int Max(int a, int b)
  {
    if (a < b) return b;
    return a;
  }

  public int Max(int a, int b, int c)
  {
    int max = a;
    if (max < b) max = b;
    if (max < c) max = c;
    return max;
  }

  public int Max(int a, int b, int c, int d)
  {
    int max = a;
    if (max < b) max = b;
    if (max < c) max = c;
    if (max < d) max = d;
    return max;
  }
}

Нижче наведено використання перевантаженого методу Max() класу MaxMethods

MaxMethods mm = new MaxMethods();

int max;
max = mm.Max(5, 6); // max=6 - викликається Max() з 2 параметрами
max = mm.Max(1, -3, 8); // max=8 - викликається Max() з 3 параметрами
max = mm.Max(2, 3, 5, 1); // max=5 - викликається Max() з 4 параметрами

Приклад 2. У класі AverageMethods оголошується метод Average(), що отримує масив чисел та визначає середнє арифметичне масиву. Метод має 2 перевантажені реалізації для типів int та float. Кількість параметрів у перевантажених методах Average() є однаковою, однак, типи параметрів є різні.

// перевантаження методу Average() у класі AverageMethods
class AverageMethods
{
  // реалізація методу Average() для масиву int[]
  public double Average(int[] Array)
  {
    double avg, sum=0;
    for (int i = 0; i < Array.Length; i++)
      sum += Array[i];
    avg = (double)sum / Array.Length;
    return avg;
  }

  // реалізація методу Average() для масиву float[]
  public double Average(float[] Array)
  {
    double avg, sum = 0;
    for (int i = 0; i < Array.Length; i++)
      sum += Array[i];
    avg = (double)sum / Array.Length;
    return avg;
  }
}

Нижче продемонстровано використання перевантаженого методу Average()

AverageMethods am = new AverageMethods();
double avg;

int[] A = new int[10];
float[] B = new float[10];

for (int i = 0; i < A.Length; i++)
{
  A[i] = i;
  B[i] = i * i;
}

// виклик методу Average(int[] Array)
avg = am.Average(A); // avg = 4.5

// виклик методу Average(float[] Array)
avg = am.Average(B); // avg = 28.5

Як видно з прикладу, компілятор автоматично визначає метод, який потрібно викликати, за типом його параметрів.

 

5. Які особливості перевантаження методів, які отримують параметри з модифікаторами ref і out?

Якщо спробувати оголосити різні реалізації методу, що містить однакові параметри, що відрізняються між собою тільки модифікаторами ref і out, то компілятор видасть помилку.

Наприклад. Нехай потрібно реалізувати два методи GetPi(), які повертають число p типу double. При нижченаведеному оголошенні цих методів у деякому класі

class SomeClass
{
  // методи GetPi відрізняються модифікаторами ref та out
  public void GetPi(ref double x)
  {
    x = 3.1415;
  }

  public void GetPi(out double x)
  {
    x = 3.1415;
  }
}

та спробі компіляції компілятор видасть повідомлення про помилку

SomeClass cannot define an overloaded method that differs only on parameter modifiers 'out' and 'ref'

Це означає, що модифікатори ref та out не змінюють загальну сигнатуру методу.

 

6. Які переваги дає перевантаження методів?

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

  • немає потреби в оголошенні додаткових методів з різними (відмінними) іменами для виконання подібної роботи. Цим самим спрощується та зменшується код програми, що в свою чергу веде до підвищення читабельності програми;
  • реалізується основний принцип поліморфізму – один інтерфейс, багато методів. Це є зручно, коли йде звертання за одним іменем до методу, а компілятор в залежності від параметрів сам вибирає яку реалізацію методу виконати;
  • забезпечується зручний доступ до зв’язаних разом методів на основі спільного імені;
  • перевантажені методи можуть виконувати абсолютно різну роботу, тобто мати абсолютно різний програмний код. Все це залежить від отримуваних параметрів. Однак, бажано, щоб перевантажувані методи виконували однакову роботу.


 

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

Конструктори класів можуть перевантажуватись так само як і методи.

Приклад 1. Задано клас CPoint, що реалізує точку на координатній площині. У класі оголошується два перевантажені конструктори.

// клас, що визначає точку на координатній площині
class CPoint
{
  double x, y; // внутрішні змінні класу

  // перевантажені конструктори класу
  // конструктор без параметрів
  public CPoint()
  {
    x = y = 0.0;
  }

  // конструктор отримує 2 параметри типу double
  public CPoint(double xx, double yy)
  {
    x = xx;
    y = yy;
  }

  // конструктор отримує 2 параметри типу int
  public CPoint(int xx, int yy)
  {
    x = xx;
    y = yy;
  }

  // методи доступу
  public void SetXY(double xx, double yy)
  {
    x = xx;
    y = yy;
  }

  public void GetXY(out double xx, out double yy)
  {
    xx = x;
    yy = y;
  }
}

Нижче продемонстровано використання перевантажених конструкторів класу

// перевантаження конструкторів
CPoint pt1 = new CPoint(); // виклик конструктора без параметрів
CPoint pt2 = new CPoint(2.5, 3); // виклик конструктора з параметрами типу double
CPoint pt3 = new CPoint(7, 5); // виклик конструктора з параметрами типу int

double x, y;

pt1.GetXY(out x, out y); // x = 0; y = 0
pt2.GetXY(out x, out y); // x = 2.5; y = 3
pt3.GetXY(out x, out y); // x = 7; y = 5

Приклад 2. Задано клас CCircle, що реалізує коло на координатній площині заданого радіусу. У класі реалізовано 4 конструктори, які отримують різну кількість параметрів.

Програмний код класу наступний

// клас, що реалізує коло
class Circle
{
  int x, y;
  int radius;

  // перевантажені конструктори класу
  // конструктор без параметрів
  public Circle()
  {
    x = y = 0;
    radius = 1;
  }

  // конструктор з 1 параметром
  public Circle(int radius)
  {
    x = y = 0;
    this.radius = radius;
  }

  // конструктор з 2 параметрами
  public Circle(int x,int y)
  {
    this.x = x;
    this.y = y;
    radius = 1;
  }

  // конструктор з 3 параметрами
  public Circle(int x, int y, int radius)
  {
    this.x = x;
    this.y = y;
    this.radius = radius;
  }

  // методи доступу
  public void Get(out int x, out int y, out int radius)
  {
    x = this.x;
    y = this.y;
    radius = this.radius;
  }
}

Нижче наводиться демонстрація використання перевантажених конструкторів класу

// виклик різних перевантажених конструкторів класу Circle
// виклик конструктора без параметрів
Circle c1 = new Circle(); // x = 0; y = 0; radius = 1;

// виклик конструктора з 1 параметром
Circle c2 = new Circle(5); // x = 0; y = 0; radius = 5;

// виклик конструктора з 2 параметрами
Circle c3 = new Circle(2, 4); // x = 2; y = 4; radius = 1;

// виклик конструктора з 3 параметрами
Circle c4 = new Circle(3, 5, 7); // x = 3; y = 5; radius = 7;

 

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

Мова C# дозволяє викликати один конструктор з іншого у випадку, якщо у класі є декілька перевантажених реалізацій конструкторів. Щоб з заданого конструктора викликати інший перевантажений конструктор застосовується ключове слово this. Загальна форма такого виклику наступна

constructor_name(parameters1) : this(parameters2)
{
  // ...
}

де

  • constructor_name – ім’я конструктора, що здійснює виклик перевантаженого конструктора;
  • parameters1 – параметри конструктора, який здійснює виклик перевантаженого конструктора. Цей конструктор викликається другим після виклику конструктора, позначеного ключовим словом this;
  • parameters2 – параметри перевантаженого конструктора, який означений ключовим слово this. Цей конструктор викликається першим.

 

9. Приклад виклику перевантаженого конструктора з використанням ключового слова this

Приклад. Реалізація класу CPixel, що описує піксель на екрані монітора. Піксель характеризується наступними параметрами:

  • цілочисельні координати x, y;
  • колір (color).

Клас містить 2 перевантажені конструктори. У класі продемонстровано виклик перевантаженого конструктора.

class Pixel
{
  // внутрішні змінні 
  int x, y;
  int color;

  // конструктори класу
  // конструктор з 1 параметром
  public Pixel(int _color)
  {
    x = y = 0;
    color = _color;
  }

  // конструктор з 3 параметрами - виклик з конструктора іншого конструктора
  public Pixel(int _x, int _y, int _color) : this(_color)
  {
    x = _x;
    y = _y;
  }

  // метод читання внутрішніх змінних 
  public void Get(out int _x, out int _y, out int _color)
  {
    _x = x;
    _y = y;
    _color = color;
  }
}

Виклик перевантаженого конструктора здійснюється з допомогою коду

...

public Pixel(int _x, int _y, int _color) : this(_color)
{
  x = _x;
  y = _y;
}

...

Конструктор з 3 параметрами викликає конструктор з 1 параметром. При такому виклику параметр, що є в викликаючому конструкторі, має бути обов’язково у конструкторі що викликається з допомогою this. У нашому випадку, обов’язковим є параметр _color.

Демонстрація використання класу Pixel

// виклик конструктора з конструктора
Pixel px = new Pixel(2, 5, 10); // викликається конструктор з 3 параметрами
int x, y, color;

px.Get(out x, out y, out color); // x = 2; y = 5; color = 10;

 


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