Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5677 / 802 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 7:

Наследование и полиморфизм

< Лекция 6 || Лекция 7: 123456 || Лекция 8 >

Абстрактные функции и абстрактные классы

При реализации принципа наследования базовый класс воплощает НАИБОЛЕЕ ОБЩИЕ черты разрабатываемого семейства классов. Поэтому на этапе разработки базового класса часто бывает достаточно лишь обозначить множество функций, которые будут определять основные черты поведения объектов — представителей производных классов.

Если базовый класс объявляется, исходя из следующих предпосылок:

  • базовый класс используется исключительно как основа для объявления классов — наследников,
  • базовый класс никогда не будет использован для определения объектов,
  • часть функций — членов (возможно, все) базового класса в обязательном порядке переопределяется в производных классах, то определение таких функций даже в самых общих чертах (заголовок функции и тело, содержащее вариант оператора return ) в базовом классе лишено всякого смысла.
class X
{
public int f0()
{ 
// Если, в соответствии с замыслом разработчика, этот код ВСЕГДА 
будет недоступен,
// то зачем он в принципе нужен?
return 0; 
 } 
}

class Y:X 
{
new public int f0()
{
::::::::::
// Здесь размещается код переопределенной функции. 
::::::::::
return 0;
} 
}

Такой код никому не нужен, и C# позволяет избегать подобных странных конструкций. Вместо переопределяемой "заглушки" можно использовать объявление абстрактной функции.

Синтаксис объявления абстрактной функции предполагает использование ключевого слова abstract и полное отсутствие тела. Объявление абстрактной функции завершается точкой с запятой.

Класс, содержащий вхождения абстрактных (хотя бы одной!) функций, также должен содержать в заголовке объявления спецификатор abstract.

В производном классе соответствующая переопределяемая абстрактная функция обязательно должна включать в заголовок функции спецификатор override. Его назначение – явное указание факта переопределения абстрактной функции.

Абстрактный класс фактически содержит объявления нереализованных функций базового класса. На основе абстрактного класса невозможно определить объекты. Попытка создания соответствующего объекта — представителя абстрактного класса приводит к ошибке, поскольку в классе не определены алгоритмы, определяющие поведение объекта:

abstract class X // Абстрактный класс с одной абстрактной функцией.
{
public abstract int f0(); 
}
class Y:X 
{
// Переопределение абстрактной функции должно
// содержать спецификатор override. 
public override int f0() 
{
 ::::::::::
return 0;
} 
}
::::::::::
static void Main(string[] args)
{
X x = new X(); // NO!
Y y0 = new Y(125);
// Работает переопределенная абстрактная функция!
y0.f0();	 
}

Еще пример:

using System;
namespace Interface01
{
// Абстрактный класс.  
abstract class aX1
{
public int xVal;
// Его конструкторы могут использоваться при построении
// объектов класcов-наследников.
public aX1(int key)
{   
Console.WriteLine("aX1({0})...", key);
xVal = key;
}

public aX1()
{
Console.WriteLine("aX1()...");
xVal = 0;
}
public void aX1F0(int xKey)
{
xVal = xKey;
} 

public abstract void aX2F0();
}

class bX1:aX1
{
new public int xVal; 

public bX1():base(10)
{
xVal = 125;
Console.WriteLine
         ("bX1():base(10)... xVal=={0},base.xVal=={1}...", xVal, base.xVal);
}

public bX1(int key):base(key*10)
{
xVal = key;
Console.WriteLine("bX1({0}):base({1})...", xVal, base.xVal);
}
	
public override void aX2F0()
{
xVal = xVal*5;
base.xVal = base.xVal*100;
}

}

class Class1
{
static void Main(string[] args)
{
// Ни при каких обстоятельствах не может служить основой для
// построения объектов. Даже если не содержит ни одного объявления
// абстрактной функции.
//aX1 x = new aX1();

bX1 x0 = new bX1();
x0.aX1F0(10); // Вызвали неабстрактную функцию базового абстрактного класса.
bX1 x1 = new bX1(5);
x1.aX2F0();//Вызвали переопределенную функцию. В базовом классе это
// абстрактная функция.
}
}
}
Листинг 7.3.

Ссылка на объект базового класса

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

using System;
namespace Inheritance_3
{
class X
{//===================================================
public int q0 = 0;
public int q = 0;

public void fun0()
{
Console.WriteLine("class X, fun0()");
} 	 

public void fun1()
 {
Console.WriteLine("class X, fun1()");
 } 	 
}//===================================================

class Y:X
{//===================================================
new public int q = 0;
new public void fun1()
 {
Console.WriteLine("class Y, fun1()");
 } 	 

public void fun00()
 {
Console.WriteLine("class Y, fun00()"); 
 }
}//===================================================
class Z:X
{//===================================================
new public int q = 0;
new public void fun1()
 {
Console.WriteLine("class Z, fun1()");
 } 	 

public void fun00()
 {
Console.WriteLine("class Z, fun00()");
 }
}//===================================================

class StartClass
{//===================================================
static void Main(string[] args)
{
X x = null; // Просто ссылка!
// Объекты – представители производных классов-наследников. 
Y y = new Y(); y.fun0(); y.fun00(); y.fun1();
Z z = new Z(); z.fun0(); z.fun00(); z.fun1();
// Настройка базовой ссылки.
x = y; x.fun0(); x.fun1(); x.q = 100; x.q0 = 125;
x = z; x.fun0(); x.fun1(); x.q = 100; x.q0 = 125;
}	
}//===================================================

}
Листинг 7.4.

Результат:

class X, fun0()
class Y, fun00()
class Y, fun1()
class X, fun0()
class Z, fun00()
class Z, fun1()
class X, fun0()
class X, fun1()
class X, fun0()
class X, fun1()

Вопросов не будет, если рассмотреть схему объекта — представителя класса Y.


Вот что видно из ссылки на объект класса X, настроенного на объект — представитель производного класса. Схема объекта — представителя класса Z и соответствующий "вид" от ссылки x выглядят аналогичным образом.

< Лекция 6 || Лекция 7: 123456 || Лекция 8 >
kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2