Московский государственный университет имени М.В.Ломоносова
Опубликован: 01.11.2004 | Доступ: свободный | Студентов: 11275 / 456 | Оценка: 4.12 / 4.01 | Длительность: 19:20:00
ISBN: 978-5-9556-0077-9
Специальности: Программист
Лекция 16:

C#. Механизмы наследования.Абстрактные классы. Интерфейсы

< Лекция 15 || Лекция 16: 12 || Лекция 17 >
Аннотация: В лекции описываются механизмы наследования языка C#, определяется понятие производного класса и вложенного класса, приводится механизм применения виртуальных методов. Описывается использование абстрактных классов и интерфейсов.

Механизмы наследования

Объявление класса в языке C# создает новый ссылочный тип, определяющий как описание методов, так и их реализацию.

Объявление интерфейса создает новый ссылочный тип, который специфицирует описание методов и имена некоторых констант, но не определяет саму реализацию.

Интерфейс может быть объявлен для расширения одного или нескольких интерфейсов.

Наследование позволяет определять новые классы в терминах существующих классов. В языке C# поддерживается только простое наследование: любой подкласс является производным только от одного непосредственного суперкласса. При этом любой класс может наследоваться от нескольких интерфейсов.

Производные классы

В среде VisualStudio.NET новый производный класс можно создать, используя окно ClassView (выполнив в нем команду контекстного меню Add|Add Class). Рисунок 16.1 иллюстрирует страницы диалога C# Class Wizard, предлагаемого средой VisualStudio.NET для создания нового класса.

Диалог C# Class Wizard

Рис. 16.1. Диалог C# Class Wizard

Имя создаваемого класса указывается в поле Class Name на странице Class Options диалога C# Class Wizard.

В поле Namespace указывается пространство имен, к которому будет принадлежать создаваемый класс. По умолчанию проект размещается в пространстве имен, одноименным с именем проекта.

В поле Access выбирается модификатор доступа для создаваемого класса.

Для класса в языке C# возможно использование двух модификаторов доступа:

  • public - определяет, что нет ограничений на использование класса;
  • internal - определяет, что класс будет доступен для файлов, входящих в ту же сборку.

Сборка - это физический файл, который состоит из нескольких PE-файлов (portable executable), генерируемых компилятором среды .NET. В сборку входит декларация (manifest), содержащая описание сборки для управляющей среды .NET.

Класс может иметь один из следующих модификаторов класса:

  • abstract - определяет, что класс должен быть использован только как базовый класс других классов. Такие классы называются абстрактными классами ;
  • sealed - определяет, что класс нельзя использовать в качестве базового класса. Такие классы в языке C# иногда называются изолированными классами.

Очевидно, что изолированный класс не может быть одновременно и абстрактным классом.

Объявление класса может иметь следующее формальное описание:

МодификаторДоступа МодификаторКласса class ИмяКласса 
      : ИмяНаследуемогоКласса
              {ТелоКласса
              }

Тело класса содержит описание переменных, методов и вложенных классов и заключается в фигурные скобки. В частном случае тело класса может не содержать ни одного объявления.

Например:

namespace CA1
{
  public abstract class Class2 : CA1.Class1
  {
    public Class2()
    {
      // TODO: Add constructor logic here
    }
  }
}

Методы - члены класса

В среде VisualStudio.NET добавить в класс новый метод можно, используя контекстное меню окна Class View. На рис. 16.2 приведен диалог C# MetodWizard, позволяющий определить модификаторы метода и список формальных параметров.

Диалог C# MetodWizard

Рис. 16.2. Диалог C# MetodWizard

Язык C# поддерживает следующие модификаторы метода члена класса:

  • static - определяет статический метод, доступный без создания экземпляра класса;
  • abstract - определяет абстрактный метод, который является членом абстрактного класса;
  • virtual - метод, реализация которого может быть переопределена в производных классах;
  • extern - метод, имеющий реализацию вне данного класса (внешний метод);
  • override - метод, выполняющий переопределение виртуальной функции, наследуемой от базового класса;
  • new - метод, скрывающий в производном классе наследуемый метод с тем же именем (если ключевое слово не указано, то имя скрывается, но при компиляции отображается предупреждение warning).

Порядок указания модификаторов доступа и модификаторов метода несущественен.

Виртуальные и абстрактные методы всегда должны указываться с модификатором доступа public.

Виртуальные методы

Виртуальные методы объявляются в базовом классе с ключевым словом virtual, а в производном классе могут быть переопределены. Метод, который переопределяет виртуальный, указывается ключевым словом override. Прототипы виртуальных методов как в базовом, так и в производном классе должны быть одинаковы.

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

На этапе компиляции строится только таблица виртуальных методов, а конкретный адрес проставляется уже на этапе выполнения.

При вызове метода - члена класса действуют следующие правила:

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

При позднем связывании определение вызываемого метода происходит на этапе выполнения (а не при компиляции) в зависимости от типа объекта, для которого вызывается виртуальный метод.

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

Например:

using System;
namespace MyDerriv1
{
class Class1
  {
  static void Main(string[] args)
  {
       // Тип объекта и тип ссылки совпадают
      CA var1; var1=new CA();  
    // Вызывается метод класса CA
    Console.WriteLine (var1.F1());
    // Вызывается метод класса CA
    Console.WriteLine (var1.F2());
    // Тип объекта - CB , а тип ссылки - CA
    CA var2; var2=new CB();
    // Вызывается метод класса CA
    Console.WriteLine (var2.F1());
    // Вызывается метод класса CB
    Console.WriteLine (var2.F2());
  }
}
}
// Класс CA
using System;
namespace MyDerriv1
{
public class CA
{  public CA()    {    }
  public int F1()  {  return 1;  }
  public virtual string F2()
      {return "Метод F2 класса CA";}
}
}
// Класс CB
using System;
namespace MyDerriv1
{  public class CB : MyDerriv1.CA
  {
  public CB()  {    }
  public int F1()  {return 2;  }
    // Переопределение виртуального метода F2
  public override string F2()    
      { return "Метод F2 класса CB"; }
}
}
Листинг 16.1.

Абстрактные классы

Абстрактным классом называется класс, который содержит один или несколько абстрактных методов.

Абстрактный класс не может использоваться для создания объектов.

Как правило, абстрактный класс описывает некий интерфейс, который должен быть реализован всеми его производными классами.

Абстрактный метод языка C# не имеет тела метода и аналогичен чисто виртуальному методу языка C++.

Например:

public abstract int M1(int a, int b);

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

По умолчанию при создании абстрактного класса в среде VisualStudio .NET в формируемый абстрактный класс автоматически вставляется только один метод - конструктор без параметров.

< Лекция 15 || Лекция 16: 12 || Лекция 17 >
Александр Демьяненко
Александр Демьяненко

Можно ли сдавать один и тот же тест несколько раз?
Или же один и тот же тест можно сдать лишь однажды?

Максим Стогний
Максим Стогний

Добрый день!

Скажите, пожалуйста, если в терминологии объектно-ориентированного программирования функции также называются методами или методами - членами класса, в примере объявления указателя на метод использовали в формальном описании оба названия:

тип_метода (имя_класса::*имя_метода_указателя)
    (список параметров);
тип_функции (*имя_ функции_указателя)
    (список параметров);

при этом можно было  тип_функции во втором описании заменить на тип_метода? Т.е.:

тип_метода (*имя_ метода_указателя)
    (список параметров);