C#. Доступ к элементам класса из экземпляров классов, образовывающих иерархию. Особенности применения ссылки на базовый класс.




Доступ к элементам класса из экземпляров классов, образовывающих иерархию. Особенности применения ссылки на базовый класс. Ключевые слова as, is. Способы вызова методов с одинаковыми именами в иерархиях наследования. Статический полиморфизм

В данной теме изучается:

  • доступ с помощью экземпляров к элементам классов, образовывающих иерархию;
  • доступ к с помощью ссылки на базовый класс к элементам классов, образовывающих иерархию;
  • изучение особенностей использования ключевых слов is, as;
  • способы вызова методов с одинаковыит именами в иерархии классов.

Содержание


Поиск на других ресурсах:

1. Использование экземпляров классов, образовывающих иерархию. Особенности доступа к элементам базового класса из экземпляра унаследованного класса

Если классы образовывают иерархию наследования, то можно объявлять объекты (экземпляры) любого из классов иерархии. Исключение касается только абстрактных классов и интерфейсов, экземпляры которых невозможно объявить.
Если объявлены экземпляры разных классов, то с помощью этих экземпляров можно получить доступ к public-элементам этих классов. Если некоторый класс есть унаследован от другого класса, то из экземпляра этого класса можно получить доступ:

  • ко всем public-элементам данного класса;
  • к тем public-элементам базового класса, имена которых не «прячутся» (перекрываются) элементами данного класса.
    Из экземпляра класса невозможно получить доступ к элементам классов, унаследованных от данного.

Рисунок 1 демонстрирует доступ из экземпляров objA, objB, objC классов A, B, C которые образовывают иерархию наследования. Из любого экземпляра делается попытка вызвать методы его класса и методы других классов иерархии.

C#. Наследование. Доступ к элементам классов из экземпляров этих классов

Рисунок 1. Доступ к элементам классов из экземпляров этих классов

 

2. Пример, который демонстрирует доступ из экземпляров классов, образовывающих иерархию

Ниже приводится текст демонстрационной программы которая соответствует рисунку 1. Программа создана по шаблону Console Application.

using System;
using static System.Console;

namespace C_sharp
{
  // Класс A - базовый класс
  class A
  {
    public void Show()
    {
      WriteLine("Method A.Show()");
    }

    public void ShowA()
    {
      WriteLine("Method A.ShowA()");
    }
  }

  // Класс B - унаследован от класса A
  class B : A
  {
    public new void Show()
    {
      WriteLine("Method B.Show()");
    }

    public void ShowB()
    {
      WriteLine("Method B.ShowB()");
    }
  }

  // Класс C - унаследован от класса B
  class C : B
  {
    public new void Show()
    {
      WriteLine("Method C.Show()");
    }

    public void ShowC()
    {
      WriteLine("Method C.ShowC()");
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Экземпляры (объекты) классов A, B, C
      A objA = new A();
      B objB = new B();
      C objC = new C();

      // 2. Доступ к элементам с помощью objA
      objA.Show(); // вызывается A.Show()
      objA.ShowA(); // вызывается A.ShowA()
      // objA.ShowB(); - ошибка, нету доступа: базовый класс не может
      // расширяться к возможностям производного
      // objA.showC(); - ошибка, также нету доступа

      WriteLine("-------------------");

      // 3. Доступ к элементам из объекта objB класса B
      objB.Show(); // по умолчанию вызывается B.Show(), потому что
      // метод B.Show() "скрывает" (переопределяет) метод A.Show()
      objB.ShowA(); // вызов метода базового класса A.ShowA()
      objB.ShowB(); // B.ShowB()
      // objB.ShowC(); - ошибка, нету доступа: базовый класс не может
      // расширяться до возможностей производного класса

      WriteLine("-------------------");
      // 4. Доступ к элементам из объекта objC класса C
      objC.Show(); // C.Show() - данный метод переопределяет методы базовых классов
      objC.ShowA(); // A.ShowA()
      objC.ShowB(); // B.ShowB()
      objC.ShowC(); // C.ShowC()
    }
  }
}

Результат выполнения программы

Method A.Show()
Method A.ShowA()
-------------------
Method B.Show()
Method A.ShowA()
Method B.ShowB()
-------------------
Method C.Show()
Method A.ShowA()
Method B.ShowB()
Method C.ShowC()

 

3. Ссылка на базовый класс в иерархии классов. Особенности применения

Как известно, на любой класс может быть объявлена ссылка. Если классы образовывают иерархию наследования, то для этих классов можно определить следующее правило (правило 1): ссылке на базовый класс можно присвоить значение экземпляра (объекта) производного класса.
То есть, после того, как объявлена ссылка на базовый класс, этой ссылке можно присваивать значения объекта (экземпляра) любого класса из иерархии. Таким образом, можно «двигаться» с помощью ссылки по созданным экземплярам классов из иерархии.

Рисунок 2 демонстрирует правило 1 на примере иерархии из 3 классов A, B, C.

C#. Наследование. Присвоение ссылке на базовый класс значений экземпляров производных классов

Рисунок 2. Присвоение ссылке на базовый класс значений экземпляров производных классов

После того, как ссылке на базовый класс присвоены значения одного из экземпляров класса из иерархии, можно попробовать использовать элементы этого экземпляра (вызвать методы, свойства, и т.п.). В этом случае уместным есть правило 2: если ссылка на базовый класс получает значение объекта (экземпляра) производного класса, то доступ по этой ссылке есть только к элементам базового класса. Рисунок 3 демонстрирует использование правила 2.

C#. Наследование. Демонстрация доступа к элементам классов с помощью ссылки на базовый класс

Рисунок 3. Демонстрация доступа к элементам классов A, B с помощью ссылки rA на базовый класс A

Как видно из рисунка 2, с помощью ссылки на базовый класс можно доступиться к элементам базового класса A. К элементам унаследованного класса B нету доступа. Чтобы организовать доступ к элементам унаследованного класса B нужно использовать способы приведения типа A к типу B (смотрите пункт 5).

 



4. Пример, который демонстрирует ограничения, которые могут возникнуть при использовании ссылки на базовый класс

В примере продемонстрированы ограничения доступа к элементам экземпляра objB производного класса B из ссылки rA на базовый класс A. Невозможно вызвать элементы класса B без явного приведения типа и использования операторов is, as.

using System;
using static System.Console;

namespace C_sharp
{
  // Класс A - базовый класс
  class A
  {
    public void Show()
    {
      WriteLine("Method A.Show()");
    }

    public void ShowA()
    {
      WriteLine("Method A.ShowA()");
    }
  }

  // Класс B - унаследован от класса A
  class B : A
  {
    public void Show()
    {
      WriteLine("Method B.Show()");
    }

    public void ShowB()
    {
      WriteLine("Method B.ShowB()");
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Ссылка на базовый класс
      A rA;

      // 2. Экземпляр класса A
      A objA = new A();

      // 3. Экземпляр класса B
      B objB = new B();

      // 4. Ссылке базового класса можно присваивать
      // значение ссылки базового класса - это естественно
      rA = objA;

      // 5. Использование элементов по ссылке
      rA.Show(); // вызывается A.Show()
      rA.ShowA(); // A.ShowA()
      // rA.ShowB(); // - ошибка, нету доступа к ShowB()

      // 6. Ссылке базового класса можно присваивать
      // значение ссылки производного класса (правило 1)
      rA = objB; // rA ссылается на экземпляр objB класса B
      rA.Show(); // опять вызывается A.Show() - важно
      rA.ShowA(); // A.ShowA()
      // rA.ShowB(); // ошибка, опять нету доступа к ShowB()

      // чтобы вызвать B.Show() нужно реализовать приведение
      // ссылки rA к типу B явно.
    }
  }
}

Результат выполнения программы

Method A.Show()
Method A.ShowA()
Method A.Show()
Method A.ShowA()

 

5. Способы организации доступа к элементам производного класса с помощью ссылки на базовый класс. Ключевые слова is, as

Как было определено в предыдущем пункте, если ссылка на базовый класс ссылается на экземпляр производного класса, то с помощью этой ссылки существует доступ только к элементам базового класса. Однако, это правило можно изменить и получить доступ к элементам производных классов.
Чтобы с помощью ссылки на базовый класс получить доступ элементам производного класса, нужно использовать один из трех возможных способов.

  • использовать явное приведение к типу унаследованного класса;
  • использовать ключевое слово as, которое осуществляет попытку приведения одного типа к другому;
  • использовать ключевое слово as в сочетании с проверкой на совместимость типов. Проверка на совместимость использует ключевое слово is.

На рисунке 4 изображены все 3 способа для заданных классов A, B которые образовывают иерархию.

C#. Наследование. Способы доступа к элементам производного класса с помощью ссылки на базовый класс

Рисунок 4. Способы доступа к элементам производного класса с помощью ссылки на базовый класс

 

6. Пример, который демонстрирует способы организации доступа по ссылке к элементам производного класса

В примере демонстрируется 3 способы организации доступа к методу Show() производного класса B из ссылки на базовый класс A. Реализованные способы демонстрируют статический полиморфизм, если централизованный вызов метода формируется на этапе компиляции (во время приведения типа).

using System;
using static System.Console;

namespace C_sharp
{
  // Класс A - базовый клас
  class A
  {
    public void Show()
    {
      WriteLine("Method A.Show()");
    }

    public void ShowA()
    {
      WriteLine("Method A.ShowA()");
    }
  }

  // Класс B - унаследован от класса A
  class B : A
  {
    public new void Show()
    {
      WriteLine("Method B.Show()");
    }

    public void ShowB()
    {
      WriteLine("Method B.ShowB()");
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Ссылка на базовый класс
      A rA;

      // 2. Экземпляр класса A
      A objA = new A();

      // 3. Экземпляр класса B
      B objB = new B();

      // 4. Доступ к экземпляру базового класса A
      rA = objA;
      rA.Show(); // вызывается A.Show()
      rA.ShowA(); // A.ShowA()
      // rA.ShowB(); - ошибка, нету доступа

      // 5. Доступ к элементам экземпляра objB
      // с помощью ссылки на A
      rA = objB; // rA ссылается на objB

      // 5.1. Способ №1. Приведение к типу B - необходимо,
      // чтобы вызов rA.Show() => objB.Show().
      try
      {
        // rA привести к типу B
        ((B)rA).Show(); // вызывается B.Show()
      }
      catch
      {
        // Если приведение rA к типу B не состоялось,
        // то выход
        WriteLine("Error.");
        return;
      }

      // 5.2. Способ №2. Использование ключевого слова as.
      // Ключевове слово as используется в случаях,
      // когда нужно реализовать попытку приведения
      // одного типа к другому.
      rA = objB;
      if ((rA as B) != null)
        (rA as B).Show(); // B.Show()

      // 5.3. Способ №3. Использование сочетания ключевых слов is, as.
      // Ключевое слово is используется для определения
      // совместимости двух типов. Если типы совместимы, то результат
      // равен true, иначе false.
      if (rA is B)
        (rA as B).Show(); // B.Show()
    }
  }
}

 


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

 


 

0
fb-share-icon20