Перегрузка методов в классах. Примеры. Преимущество перегрузки методов. Перегрузка конструкторов

Перегрузка методов в классах. Примеры. Преимущество перегрузки методов. Перегрузка конструкторов


Содержание



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. Задан класс Circle, реализующий окружность на координатной плоскости заданного радиуса. В классе реализованы 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;

 


Связанные темы