Доступ к членам базового класса из производного
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

 

Поля и методы, объявленные в базовом классе с модификатором private, будут доступны только в методах базового класса. С помощью модификатора protected можно предоставить доступ к полям и методам базового класса для методов производных классов, но не для внешних по отношению к классу методов. Пример.

 

using System;

namespace ConsoleApplication16

{

public class Person

{

   protected string ssn = "444-55-6666";

   protected string name = "John L. Malgraine";

   public virtual void GetInfo()

   {

       Console.WriteLine("Name: {0}", name);

       Console.WriteLine("SSN: {0}", ssn);

   }

}

class Employee : Person

{

   public string id = "ABC567EFG";

   public override void GetInfo()

   {

       base.name = "ttttttttttt";

       base.GetInfo();

       Console.WriteLine("Employee ID: {0}", id);

   }

}

class TestClass

{

   static void Main()

   {

       Employee E = new Employee();

       E.GetInfo();

   }

}

}

 

Базовые классы могут определять и реализовывать виртуальные методы, а производные классы могут переопределять их. Виртуальный метод не может быть статическим. Переопрелеленный метод является виртуальным и может быть переопределен. Для переопределения невиртуального метода (сокрытие) используется ключевое слово new. Модификатор new создает новый элемент с таким же именем. Пример.

 

public class BaseClass

{

   public void DoWork() { Console.WriteLine("Метод базового класса");}

}

public class DerivedClass : BaseClass

{

   public new void DoWork() { Console.WriteLine("Метод производного класса"); }

}

class Program

{

   static void Main(string[] args)

   {

       DerivedClass B = new DerivedClass();

       B.DoWork(); // Calls the new method.

       BaseClass A = new BaseClass();

       A.DoWork(); // Calls the old method.

       BaseClass AA = (BaseClass)B;

       AA.DoWork();

       BaseClass AAA = new DerivedClass();

       AAA.DoWork();

}

}

 

Сравните

public class BaseClass

{

   public virtual void DoWork() { Console.WriteLine("Метод базового класса");}

}

public class DerivedClass : BaseClass

{

   public override void DoWork() { Console.WriteLine("Метод производного класса"); }

}

class Program

{

   static void Main(string[] args)

   {

       DerivedClass B = new DerivedClass();

       B.DoWork(); // Calls the new method.

       BaseClass A = new BaseClass();

       A.DoWork(); // Calls the old method.

       BaseClass AA = (BaseClass)B;

       AA.DoWork();

       BaseClass AAA = new DerivedClass();

       AAA.DoWork();

}

}

 

Пример

Создать два класса в каждом конструктор и метод

 

using System;

namespace ConsoleApplication17

{

class Point

{

   int x;

   int y;

   public Point(int x, int y)

   {

       this.x = x;

       this.y = y;

   }

   public void Draw()

   {

       Console.WriteLine("Рисование точки в ({0}, {1})", x, y);

   }

}

class Rectangle

{

   int x;

   int y;

   int w;

   int h;

   public Rectangle(int x, int y, int w,int h)

   {

       this.x = x;

       this.y = y;

       this.w = w;

       this.h = h;

   }

   public void Draw()

   {

       Console.WriteLine("Рисование прямоугольника в ({0}, {1})", x, y);

   }

}

class ShapeApp

{

   static void Main(string[] args)

   {

       Rectangle r = new Rectangle(1, 24, 10, 20);

       r.Draw();

       Point p = new Point(10, 25);

       p.Draw();

   }

}

}

 

Создать базовый класс Shape

 

using System;

namespace ConsoleApplication17

{

class Shape

{

   protected int x;

   protected int y;

   public Shape(int x, int y)

   {

       this.x = x;

       this.y = y;

   }

}

class Point : Shape

{

   public Point(int x, int y) : base(x,y)

   {

   }

   public void Draw()

   {

       Console.WriteLine("Рисование точки в ({0}, {1})", x, y);

   }

}

class Rectangle :Shape

{

   int w;

   int h;

   public Rectangle(int x, int y, int w,int h) : base(x,y)

   {

       this.w = w;

       this.h = h;

   }

   public void Draw()

   {

       Console.WriteLine("Рисование прямоугольника в ({0}, {1})", x, y);

   }

}

class ShapeApp

{

   static void Main(string[] args)

   {

       Rectangle r = new Rectangle(1, 24, 10, 20);

       r.Draw();

       Point p = new Point(10, 25);

       p.Draw();

   }

}

}

 

 

Метод Draw класса Shape определим с ключевым словом virtual. Метод Draw производных классов с ключевым словом override

 

using System;

namespace ConsoleApplication17

{

class Shape

{

   protected int x;

   protected int y;

   public Shape(int x, int y)

   {

       this.x = x;

       this.y = y;

   }

   public virtual void Draw()

   {

   }

}

class Point : Shape

{

   public Point(int x, int y) : base(x,y)

   {

   }

   public override void Draw()

   {

       Console.WriteLine("Рисование точки в ({0}, {1})", x, y);

   }

}

class Rectangle :Shape

{

   int w;

   int h;

   public Rectangle(int x, int y, int w,int h) : base(x,y)

   {

       this.w = w;

       this.h = h;

   }

   public override void Draw()

   {

       Console.WriteLine("Рисование прямоугольника в ({0}, {1})", x, y);

   }

}

class ShapeApp

{

   static void Main(string[] args)

   {

       Shape r = new Rectangle(1, 24, 10, 20);

       r.Draw();

       Shape p = new Point(10, 25);

       p.Draw();

   }

}

}

 

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

 

В следующем фрагменте кода реализация виртуального метода Draw базового класса Shape заменяется реализацией метода Draw производного класса.

 

class Shape

{

   protected int x;

   protected int y;

   public Shape(int x, int y)

   {

       this.x = x;

       this.y = y;

   }

   public virtual void Draw()

   {

   }

}

class Point : Shape

{

   public Point(int x, int y) : base(x,y)

   {

   }

   public override void Draw()

   {

       Console.WriteLine("Рисование точки в ({0}, {1})", x, y);

   }

}

class Rectangle :Shape

{

   int w;

   int h;

   public Rectangle(int x, int y, int w,int h) : base(x,y)

   {

       this.w = w;

       this.h = h;

   }

   public override void Draw()

   {

       Console.WriteLine("Рисование прямоугольника в ({0}, {1})", x, y);

   }

}

class ShapeApp

{

   static void Main(string[] args)

   {

       Shape[] allShapes = new Shape[4];

       allShapes[0] = new Rectangle(1, 24, 10, 20);

       allShapes[1] = new Point(10, 25);

       allShapes[2] = new Point(1, 25);

       allShapes[3] = new Rectangle(1, 4, 10, 20);

       foreach (Shape s in allShapes)

       {

           s.Draw();

       }

   }

}

 

Типы перечислений

Типом перечисления называют тип, в котором описан набор пар, состоящих из символьного имени и числового значения. Тип перечисления относятся к типам значениям. Пример определения типа перечисления:

 

В примере объявляется тип перечисления  с именем Color, содержащий элементы списка перечислителя  Red, Green и Blue.

Объявление перечислени я

Объявление перечисления объявляет новый перечисляемый тип. Объявление перечисления начинается с зарезервированного слова enum и содержит определение имени, доступности, базового типа и членов перечисления.

Enum declarations

enum-declaration:
attributesopt enum-modifiersopt enum identifier enum-baseopt enum-body ;opt

объявление_перечисления:
атрибутынеобязательно модификаторы_перечислениянеобязательно enum идентификатор база_перечислениянеобязательно тело_перечисления ;необязательно

 

Каждый тип перечисления имеет соответствующий целый тип, называемый базовым типом типа перечисления. Этот базовый тип должен иметь возможность представлять все значения перечислителя, определенные в перечислении. Объявление перечисления может явно объявлять базовый тип byte, sbyte, short, ushort, int, uint, long или ulong. Тип char не может использоваться в качестве базового типа. Объявление перечисления, которое не содержит явное объявления базового типа, имеет базовый тип int.

Например:

enum Color: long
{
       Red,
       Green,
       Blue
}

Здесь объявляется перечисление с базовым типом long.








Модификаторы перечисления .

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

new
public
protected
internal
private

 

Возникает ошибка времени компиляции, если один и тот же модификатор встречается несколько раз в объявлении перечисления. Модификаторы new, protected, private допустимы только если перечисление является вложенным.

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

Тип System.Enum.

Тип System.Enum — это абстрактный базовый класс всех перечисляемых типов. члены, унаследованные от System.Enum, доступны в любом перечисляемом типе.





Примеры работы с перечислениями.

namespace ConsoleApplication3

{

class Program

{

   public enum namemethod

   {

       method1,

       method2,

       method3

   }

   static void Main(string[] args)

   {

       Console.WriteLine(Enum.GetUnderlyingType(typeof(namemethod)));

   }

}

 }

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

using System;

namespace ConsoleApplication3

{

class Program

{

   public enum namemethod

   {

       method1,

       method2,

       method3

   }

   static void Main(string[] args)

   {

   namemethod temp = (namemethod)Enum.Parse(typeof(namemethod), Console.ReadLine());

       Console.WriteLine(temp.ToString("G"));

   }

}

 }

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

using System;

namespace ConsoleApplication3

{

class Program

{

   public enum namemethod

   {

       method1,

       method2,

       method3

   }

   static void Main(string[] args)

   {

       Console.WriteLine(Enum.Format(typeof(namemethod),Int32.Parse(Console.ReadLine()),"G"));

   }

}

 }

Пример

 enum en

{

   a=9,b=10,c=11

}

class Program

{

   static void Main(string[] args)

   {

       string s = Console.ReadLine();

       en myen = (en)Enum.Parse(typeof(en), s);

       Console.WriteLine(myen.ToString("G"));

   }

}

 

Пример

 

enum en

{

   a=9,b=10,c=11

}

class Program

{

   static void Main(string[] args)

   {

       string s = Console.ReadLine();

       en myen = (en)Enum.Parse(typeof(en), s);

       Console.WriteLine(myen.ToString("G"));

       string[] mystr =Enum.GetNames(typeof(en));

       Console.WriteLine(mystr[2]);

   }

}

Пример

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ConsoleApplication1

{

enum VehicleDoors { Motorbike = 0, Sportscar = 2, Sedan = 4, Hatchback = 5 };

 

 

class Program

{

   static void Main(string[] args)

   {

       string s=Enum.GetName(typeof(VehicleDoors), 4);

           

       Console.WriteLine(s);

 

       VehicleDoors myVeh = VehicleDoors.Sportscar;

       VehicleDoors yourVeh = VehicleDoors.Motorbike;

 

                

       Console.WriteLine(myVeh.CompareTo(yourVeh));

          

       VehicleDoors hh = new VehicleDoors();

          Console.WriteLine(hh);

           

   }

}

}

 

Интерфейсы.

Интерфейс – ссылочный тип. Интерфейс представляет способ задать имя набору сигнатур методов (можно определять методы, события, индексаторы  и свойства). Интерфейс не содержит реализации методов. Класс наследует интерфейс через указание имени интерфейса и должен явно содержать реализации методов интерфейса.

Объявление интерфейса является объявлением типа, где объявляется новый тип интерфейса.

Interface declarations

interface-declaration:
attributesopt interface-modifiersopt partialopt interface identifier type-parameter-listopt
            interface-baseopt   type-parameter-constraints-clausesopt interface-body ;opt

 

объявление_интерфейса:
атрибутынеобязательно модификаторы_интерфейсанеобязательно partialнеобязательно interface             идентификатор список_параметров_типа_вариантанеобязательно база_интерфейсанеобязательно
            предложения_ограничений_параметров_типанеобязательно тело_интерфейса ;необязательно

 

модификаторы_интерфейса:
new
public
protected
internal
private

Модификатор new (protected , private ) разрешен только в том случае, если интерфейс определяется внутри класса. Модификатор new указывает, что в интерфейсе скрыт унаследованный член с таким же именем.

В теле_интерфейса определяются члены этого интерфейса.

тело_интерфейса:
{ объявления_элементов_интерфейсанеобязательно }

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

объявление_членов_интерфейса:
объявление_метода_интерфейса
объявление_свойства_интерфейса
объявление_события_интерфейса
объявление_индексатора_интерфейса

Например:

public delegate void StringListEvent(IStringList sender);

public interface IStringList
{
       void Add(string s);

       int Count { get; }

       event StringListEvent Changed;

       string this[int index] { get; set; }
}

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

К объявлениям членов интерфейса применяются следующие правила:

Имя метода должно отличаться от имен всех свойств и событий, объявленных в том же интерфейсе. Помимо этого подпись метода должна отличаться от подписей всех других методов, объявленных в том же интерфейсе, а два метода, объявленные в одном интерфейсе, не могут иметь подписи, отличающиеся только модификаторами ref и out.

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

Подпись индексатора должна отличаться от подписей всех остальных индексаторов, объявленных в том же интерфейсе.

 

В объявлении интерфейса может содержаться любое количество членов, в том числе ни одного.

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

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

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

 

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

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

 

 

provider

Тип: System.IFormatProvider
Объект IFormatProvider, предоставляющий сведения о форматировании, связанные с определенным языком и региональными параметрами.

provider переменная типа System.IFormatProvider. Нельзя создать экземпляр  интерфейса IFormatProvider с помощью оператора new.

 

 

У интерфейсов не бывает конструкторов. Можно создать переменную типа интерфейса и присвоить ей, ссылку на экземпляр класса, производного от интерфейса.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ConsoleApplication10

{

class Program

{

   static void Main(string[] args)

   {

       DateTime[] dt = new DateTime[3] { new DateTime(2012, 3, 5), new DateTime(2012, 5, 4), new DateTime(2012, 3, 7) };

 

       String st = String.Format(new System.Globalization.CultureInfo("en-US"), "{0}", dt[0]);

       Console.WriteLine(st);

   }

}

}

В перегруженном методе String.Format мы можем создать экземпляр класса System.Globalization.CultureInfo, потому что класс System.Globalization.CultureInfo наследует от интерфейса IFormatProvider

Члены интерфейса неявно имеют уровень доступа «public». Включение модификаторов в объявления членов интерфейса приведет к возникновению ошибки компилирования. Следующий код приведет к ошибке:

interface IPoint

{

// Property signatures:

public int x {get; set;}

int y {get; set;}

}

Ошибка    1     Модификатор " public" недопустим для этого элемента 

Реализация интерфейсов.



















Пример.

using System;

namespace ConsoleApplication10

{

interface IPoint

{

   // Property signatures:

   int x { get; set; }

   int y { get; set; }

}

class Point : IPoint

{

   // Fields:

   private int _x;

   private int _y;

   // Constructor:

   public Point(int x, int y)

   {

       _x = x;

       _y = y;

   }

   // Property implementation:

   public int x

   {

       get { return _x; }

       set { _x = value; }

   }

   public int y

   {

       get { return _y; }

       set { _y = value; }

   }

}

class Program

{

   static void Main()

   {

       Point p = new Point(2, 3);

       Console.Write("My Point: ");

       Console.WriteLine("x={0}, y={1}", p.x, p.y);

   }

}

}

Код приведет к ошибке:

IPoint ip = new IPoint();

 

Ошибки не будет:

using System;

namespace ConsoleApplication10

{

interface IPoint

{

   // Property signatures:

   int x { get; set; }

   int y { get; set; }

}

class Point : IPoint

{

   // Fields:

   private int _x;

   private int _y;

   // Constructor:

   public Point(int x, int y)

   {

       _x = x;

       _y = y;

   }

   // Property implementation:

   public int x

   {

       get { return _x; }

       set { _x = value; }

   }

   public int y

   {

       get { return _y; }

       set { _y = value; }

   }

}

class Program

{

   static void Main()

   {

       Point p = new Point(2, 3);

       IPoint ip = p;

       Console.Write("My Point: ");

       Console.WriteLine("x={0}, y={1}", ip.x, ip.y);

   }

}

}

В приведенном выше примере свойства в классе имеют модификатор доступа public

Если модификатор public отсутствует, то надо написать следующий код:

using System;

namespace ConsoleApplication10

{

interface IPoint

{

   // Property signatures:

   int x { get; set; }

   int y { get; set; }

}

class Point : IPoint

{

   // Fields:

   private int _x;

   private int _y;

   // Constructor:

   public Point(int x, int y)

   {

       _x = x;

       _y = y;

   }

   // Property implementation:

   int IPoint.x

   {

       get { return _x; }

       set { _x = value; }

   }

   int IPoint.y

   {

       get { return _y; }

       set { _y = value; }

   }

}

class Program

{

   static void Main()

   {

       Point p = new Point(2, 3);

       IPoint ip = p;

       Console.Write("My Point: ");

       Console.WriteLine("x={0}, y={1}", ip.x, ip.y);

   }

}

}

 Это использование явной реализации члена интерфейса. Включение в явную реализацию члена интерфейса модификаторов доступа, а также модификаторов abstract, virtual, override или static, приведет к ошибке при компилировании.

 

К явным реализациям члена интерфейса нельзя получить доступ через экземпляры классов или структур.

Явные реализации члена интерфейса позволяют разрешить неоднозначности членов интерфейса с одинаковой подписью.

 

using System;

namespace ConsoleApplication10

{

interface IPoint

{

   // Property signatures:

   int x { get; set; }

   int y { get; set; }

}

class Point : IPoint

{

   // Fields:

   private int _x;

   private int _y;

   // Constructor:

   public Point(int x, int y)

   {

       _x = x;

       _y = y;

   }

   // Property implementation:

   public int x

   {

       get { return _x; }

       set { _x = value; }

   }

   int IPoint.y

   {

       get { return _y; }

       set { _y = value; }

   }

}

class Program

{

   static void Main()

   {

       Point p = new Point(2, 3);

       IPoint ip = p;

       Console.Write("My Point: ");

       Console.WriteLine("x={0}, y={1}",p.x, ip.y);

   }

}

}



Делегаты

Объявление делегата определяет класс, производный от класса System.Delegate.

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

Объявление делегата — это объявление типа, которое объявляет новый тип делегата.

Delegate declarations

delegate-declaration:
attributesopt delegate-modifiersopt delegate return-type identifier type-parameter-listopt
            ( formal-parameter-listopt ) type-parameter-constraints-clausesopt ;

 

объявление_делегата:
атрибутынеобязательно модификаторы_делегатанеобязательно delegate возвращаемый_тип
            идентификатор список_параметров_типа_вариантанеобязательно
            ( список_формальных_параметровнеобязательно ) предложения_ограничений_параметров_типанеобязательно ;

модификаторы делегата:
new
public
protected
internal
private

Возникает ошибка времени компиляции, если один и тот же модификатор встречается несколько раз в объявлении делегата.

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

Модификаторы public, protected, internal и private управляют доступностью типа делегата. В зависимости от контекста, в котором встречается объявление делегата, некоторые из этих модификаторов запрещены.

Именем типа делегата является идентификатор.

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

Два разных типа делегатов с одинаковыми списками параметров и типом возвращаемого значения считаются разными типами делегатов.

Например

delegate int D1(int i, double d);

delegate int D2(int c, double d);

Объявление_делегата — это единственный способ объявить тип делегата. Тип делегата является типом класса, производного от System.Delegate. Типы делегатов неявно sealed, поэтому никакие производные типы от типа делегата не допускаются. Недопустимо также производить тип класса не делегата от System.Delegate. Обратите внимание, что System.Delegate сам не является типом делегата; это тип класса, от которого производятся все типы делегатов.

 

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

Делегаты объединяются с помощью бинарных операторов + и +=. Делегат можно удалить из объединения делегатов с помощью бинарных операторов - и -=. Делегаты можно проверять на равенство.

В следующем примере показано создание нескольких экземпляров делегата и их соответствующие списки вызова:

delegate void D(int x);

class C
{
          public static void M1(int i) {...}

public static void M2(int i) {...}

}

class Test
{
          static void Main() {
                          D cd1 = new D(C.M1);                    // M1
                          D cd2 = new D(C.M2);                    // M2
                          D cd3 = cd1 + cd2;                         // M1 + M2
                          D cd4 = cd3 + cd1;                         // M1 + M2 + M1
                          D cd5 = cd4 + cd3;                         // M1 + M2 + M1 + M1 + M2
          }

}

При создании экземпляров cd1 и cd2 каждый из них инкапсулирует один метод. При создании экземпляра cd3 его список вызова содержит два метода, M1 и M2, в этом порядке. Список вызова экземпляра cd4 содержит методы M1, M2 и M1, в этом порядке. Наконец, список вызова экземпляра cd5 содержит методы M1, M2, M1, M1 и M2, в этом порядке.





















Дата: 2019-03-05, просмотров: 272.