Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Теория_к_экзамену_ООП.doc
Скачиваний:
7
Добавлен:
01.03.2025
Размер:
422 Кб
Скачать
☆

Вопрос 18 Переопределение членов базового класса:new модификатор

Воп При объявлении членов производного класса в C# разрешено использовать те же самые имена, которые применялись при объявлении членов базового класса. Это касается как методов, так и данных — членов объявляемых классов.

В этом случае соответствующие члены базового класса считаются переопределенными.

Следующий простой фрагмент кода содержит объявления базового и производного классов. Особое внимание в этом примере следует уделить ключевому слову new в объявлении одноименных членов в производном классе. В данном контексте слово new выступает в качестве модификатора, который используется для явного обозначения переопределяемых членов базового класса:

Листинг 7.2.

using System;

namespace Inheritance_2

{

class X

{

public X(){}

public X(int key){}

public int q0;

public int q;

public void fun0()

{

Console.WriteLine("class X, function fun0()");

q = 125;

}

public void fun1()

{

Console.WriteLine("class X, function fun1()");

}

}

class Y:X

{

public Y(int key){}

public Y():base(125){}

new public int q; // Если опустить модификатор new –

new public void fun1() // появится предупреждение об ожидаемом new...

{

base.fun1(); // Обращение к переопределенным членам базового класса.

base.q = 125;

Console.WriteLine("class Y, function fun1()");

}

static void Main(string[] args)

{

Y y0 = new Y();

Y y1 = new Y(125);

// А извне переопределенные члены базового класса не видны.

y0.fun1();

y0.q = 100;

y0.fun0();

y0.q0 = 125;

}

}

}

При переопределении наследуемого члена его объявление в классе-наследнике должно предваряться модификатором new. Если этот модификатор в объявлении производного класса опустить – ничего страшного не произойдет. Транслятор всего лишь выдаст предупреждение об ожидаемом спецификаторе new в точке объявления переопределяемого члена класса.

Дело в том, что переопределенные члены базового класса при "взгляде" на производный класс "извне" не видны. В производном классе они замещаются переопределенными членами, и непосредственный доступ к этим членам возможен только из функций — членов базового и производного классов. При этом для обращения к переопределенному члену из метода производного класса используется ключевое слово base.

По мнению создателей языка C#, тот факт, что ранее (до момента его переопределения) видимый член (базового) класса стал недоступен и невидим извне (в результате его переопределения в производном классе), требует явного дополнительного подтверждения со стороны программиста.

Объявление класса может содержать вложенное (или внедренное) объявление класса. C# допускает и такие объявления:

class X

{

public class XX

{

}

}

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

class X

{

public class XX

{

}

}

class Y:X

{

new public class XX

{

}

}

Модификатор new используется при переопределении общедоступных объявлений и защищенных объявлений в производном классе для явного указания факта переопределения. Этот модификатор используется при объявлении класса-наследника в том случае, если надо скрыть факт наследования объявляемого члена класса.

public class MyBaseC

{

public int x;

public void Invoke()

{

:::::

}

}

Объявление члена класса Invoke в наследуемом классе скрывает метод Invoke в базовом классе:

public class MyDerivedC : MyBaseC

{

new public void Invoke()

{

:::::

}

}

А вот данное-член x не было скрыто в производном классе соответствующим членом, следовательно, остается доступным в производном классе.

Сокрытие имени члена базового класса в производном классе возможно в одной из следующих форм:

  • константа, поле, свойство или внедренный в класс тип или структура скрывают ВСЕ одноименные члены базового класса;

  • внедренный в класс или структуру метод скрывает в базовом классе свойства, поля, типы, обозначенные тем же самым идентификатором, а также одноименные методы с той же самой сигнатурой;

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

Одновременное использование в производном классе члена базового класса и его переопределенного потомка является ошибкой.

В этом примере и базовый BC-, и производный DC-классы используют одно и то же имя для обозначения объявляемого в обоих классах члена типа int. New-модификатор подчеркивает факт недоступности члена x базового класса в производном классе. Однако из производного класса все-таки можно обратиться к переопределенному полю базового класса с использованием полного квалифицированного имени:

using System;

public class BC

{

public static int x = 55;

public static int y = 22;

}

public class DC : BC

{

new public static int x = 100; // Переопределили член базового класса

public static void Main()

{

// Доступ к переопределенному члену x:

Console.WriteLine(x);

// Доступ к члену базового класса x:

Console.WriteLine(BC.x);

// Доступ к члену y:

Console.WriteLine(y);

}

}

В производном классе DC переопределяется вложенный класс C.

В рамках производного класса легко можно создать объект — представитель вложенного переопределенного класса C. Для создания аналогичного объекта — представителя базового класса необходимо использовать полное квалифицированное имя:

using System;

public class BC

{

public class C

{

public int x = 200;

public int y;

}

}

public class DC:BC

{

new public class C // Вложенный класс базового класса скрывается

{

public int x = 100;

public int y;

public int z;

}

public static void Main()

{

// Из производного класса виден переопределенный вложенный класс:

C s1 = new C();

// Полное имя используется для доступа к классу, вложенному в базовый:

BC.C s2 = new BC.C();

Console.WriteLine(s1.x);

Console.WriteLine(s2.x);

}

}