Переменные базового класса и производного класса
Стр 1 из 2Следующая ⇒ Наследование. Абстрактные классы Класс в С# может иметь произвольное количество потомков и только одного предка. При описании класса имя его предка записывается в заголовке класса после двоеточия. Если имя предка не указано, предком считается базовый класс всей иерархии System.Object. Синтаксис наследования:
[атрибуты] [спецификаторы] class имя_класса [: предки] { тело_класса} Класс, который наследуется, называется базовым. Класс, который наследует базовый класс, называется производным. Производный класс, наследует все переменные, методы, свойства, операторы и индексаторы, определенные в базовом классе, кроме того в производный класс могут быть добавлены уникальные элементы или переопределены существующие. Использование защищенного доступа Public - открыты для доступа. Если убрать public, то поля автоматически станут закрытыми для доступа (private), в том числе и для доступа из производного класса. Решить проблему доступа к закрытым полям базового класса из производного можно двумя способами: используя свойства класса или спецификатор protected. При объявлении какого-то члена класса с помощью спецификатора protected, он становится закрытым для всех классов, кроме производных.
Наследование конструкторов В иерархии классов как базовые, так и производные классы могут иметь собственные конструкторы. При этом конструктор базового класса создает часть объекта, соответствующую базовому классу, а конструктор производного класса — часть объекта, соответствующую производному классу. Так как базовый класс не имеет доступа к элементам производного класса, то их конструкторы должны быть раздельными. Если же конструкторы определены и в базовом, и в производном классе, то процесс создания объектов несколько усложняется, т.к. должны выполниться конструкторы обоих классов. В этом случае используется ключевое слово base, которое имеет два назначения:
1) позволяет вызвать конструктор базового класса: Производный класс может вызывать конструктор, определенный в его базовом классе, используя расширенную форму объявления конструктора и ключевое слово base. Формат расширенного объявления:
конструктор_производного_класса (список_параметров): base (список_аргументов) { тело конструктора }
где с помощью элемента списка аргументов передаются параметры конструктору базового класса.
В общем случае с помощью ключевого слова base можно вызвать конструктор любой формы, определенный в базовом классе. Реально же выполнится тот конструктор, параметры которого будут соответствовать переданным при вызове аргументам. Например:
2) позволяет получить доступ к члену базового класса, который скрыт "за" членом производного класса. В этом случаеключевое слово base действует подобно ссылке this, за исключением того, что ссылка base всегда указывает на базовый класс для производного класса, в котором она используется. В этом случае формат ее записи выглядит следующим образом:
base.член_класса
Здесь в качестве элемента член_класса можно указывать либо метод, либо поле экземпляра. Эта форма ссылки base наиболее применима в тех случаях, когда имя члена в производном классе скрывает член с таким же именем в базовом классе.
Несмотря на то, что метод Show в классе DemoLine скрывает одноименный метод в классе DemoPoint, ссылка base позволяет получить доступ к методу Show в базовом классе. Аналогично с помощью ссылки base можно получить доступ к одноименным полям базового класса.
Многоуровневая иерархия До сих пор мы рассматривали простой тип иерархии классов, который состоит из одного базового и одного производного класса. В общем случае можно построить иерархию классов, состоящую из любого количества уровней наследования. Рассмотрим следующую иерархию классов:
class DemoPoint { protected int x; protected int y; public void Show() { Console.WriteLine("точка на плоскости: ({0}, {1})",x, y); } public DemoPoint (int x, int y) { this.x=x; this.y=y; } }
class DemoShape: DemoPoint { protected int z; new public void Show() { Console.WriteLine("точка в пространстве: ({0}, {1}, {2})", x, y, z); } public DemoShape(int x, int y, int z):base(x, y) { this.z=z; } }
class DemoLine: DemoPoint { protected int x2; protected int y2; new public void Show() { Console.WriteLine("отрезок на плоскости: ({0}, {1})-({2},{3})",x,y, x2, y2); } public DemoLine(int x1, int y1, int x2, int y2):base(x1, y1) { this.x2 = x2; this.y2 = y2; } }
class DemoTriangle: DemoLine { protected int x3; protected int y3; new public void Show() { Console.WriteLine("треугольник на плоскости: ({0}, {1})-({2},{3})-({4},{5})",x,y, x2, y2, x3, y3); } public DemoTriangle(int x1, int y1, int x2, int y2, int x3, int y3):base(x1, y1, x2, y2) { this.x3 = x3; this.y3 = y3; } }
class Program { static void Main() { DemoPoint point = new DemoPoint(1,1); point.Show(); DemoShape pointShape = new DemoShape(1,1,1); pointShape.Show(); DemoLine line = new DemoLine(2, 2, 10, 10); line.Show(); DemoTriangle triangle = new DemoTriangle (0,0,0,3,4,0); triangle.Show(); } }
Переменные базового класса и производного класса С# является языком со строгой типизацией, в нем требуется строгое соблюдение совместимости типов с учетом стандартных преобразований типов. Из чего следует, что переменная одного типа обычно не может ссылаться на объект другого ссылочного типа. За одним небольшим исключением – ссылочная переменная базового класса может ссылаться на объект любого производного класса. Продемонстрируем это на примере:
class DemoPoint { public int x; public int y; public void Show() { Console.WriteLine("точка на плоскости: ({0}, {1})",x, y); } public DemoPoint (int x, int y) { this.x=x; this.y=y; } }
class DemoShape: DemoPoint { public int z; new public void Show() { Console.WriteLine("точка в пространстве: ({0}, {1}, {2})", x, y, z); } public DemoShape(int x, int y, int z):base(x, y) { this.z=z; } }
class Program { static void Main() { DemoPoint point1 = new DemoPoint(0,1); Console.WriteLine("({0}, {1})",point1.x,point1.y); DemoShape pointShape = new DemoShape(2,3,4); Console.WriteLine("({0}, {1}, {2})",pointShape.x, pointShape.y, pointShape.z); DemoPoint point2=pointShape; //допустимая операция //ошибка - не соответствие типов указателей //pointShape=point1; Console.WriteLine("({0}, {1})", point2.x, point2.y); //ошибка, т.к. в классе DemoPoint нет поля z //Console.WriteLine("({0}, {1}, {2})", point2.x, point2.y, point2.z);
} } Ошибка возникнет и при попытке через объект point2 обратиться к методу Show. Например, point2.Show(). В этом случае компилятор не сможет определить, какой метод Show вызвать – для базового или для производного класса. Для решения данной проблемы можно воспользоваться таким понятием как полиморфизм, который основывается на механизме виртуальных методов.
Виртуальные методы Виртуальный метод – это метод, который объявлен в базовом классе с использованием ключевого слова virtual, и затем переопределен в производном классе с помощью ключевого слова override. При этом если реализована многоуровневая иерархия классов, то каждый производный класс может иметь свою собственную версию виртуального метода. Этот факт особенно полезен в случае, когда доступ к объекту производного класса осуществляется через ссылочную переменную базового класса. В этой ситуации С# сам выбирает какую версию виртуального метода нужно вызвать. Этот выбор производится по типу объекта, на которую ссылается данная ссылка. Например:
class DemoPoint //базовый класс { protected int x; protected int y; public virtual void Show() //виртуальный метод { Console.WriteLine("точка на плоскости: ({0}, {1})",x, y); } public DemoPoint (int x, int y) { this.x=x; this.y=y; } } class DemoShape: DemoPoint //производный класс { protected int z; public override void Show() //перегрузка виртуального метода { Console.WriteLine("точка в пространстве: ({0}, {1}, {2})", x, y, z); }
public DemoShape(int x, int y, int z):base(x, y) //конструктор производного класса { this.z=z; }
} class DemoLine: DemoPoint //производный класс { protected int x2; protected int y2; public override void Show() //перегрузка виртуального метода { Console.WriteLine("отрезок на плоскости: ({0}, {1})-({2},{3})",x,y, x2, y2); } public DemoLine(int x1, int y1, int x2, int y2):base(x1, y1) { this.x2 = x2; this.y2 = y2; } }
class Program { static void Main() { DemoPoint point1 = new DemoPoint(0,1); point1.Show(); DemoShape pointShape = new DemoShape(2,3,4); pointShape.Show(); DemoLine line = new DemoLine(0,0, 10, 10); line.Show(); Console.WriteLine(); //использование ссылки базового класса на объекты производных классов DemoPoint point2=pointShape; point2.Show(); point2=line; point2.Show(); } } Таким образом, благодаря полиморфизму через ссылочную переменную возможно обращаться к объектам разного типа, а также с помощью одного и того же имени выполнять различные действия.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|