Следует особо подчеркнуть, что доступ к конкретным членам класса определяется типом переменной ссылки на объект, а не типом объекта, на который она ссылается. Это означает, что если ссылка на объект производного класса присваивается переменной ссылки на объект базового класса, то доступ разрешается только к тем частям этого объекта, которые определяются базовым классом. Именно поэтому переменной х2 недоступен член b класса Y, когда она ссылается на объект этого класса. И в этом есть своя логика, поскольку базовому классу ничего не известно о тех членах, которые до-
бавлены в производный от него класс. Именно поэтому последняя строка кода в приведенном выше примере была закомментирована.
Несмотря на кажущийся несколько отвлеченным характер приведенных выше рас-суждений, им можно найти ряд важных применений на практике. Одно из них рассматривается ниже, а другое — далее в этой главе, когда речь пойдет о виртуальных методах.
Один из самых важных моментов для присваивания ссылок на объекты производного класса переменным базового класса наступает тогда, когда конструкторы вызываются в иерархии классов. Как вам должно быть уже известно, в классе нередко определяется конструктор, принимающий объект своего класса в качестве параметра. Благодаря этому в классе может быть сконструирована копия его объекта. Этой особенностью можно выгодно воспользоваться в классах, производных от такого класса. В качестве примера рассмотрим очередные варианты классов TwoDShape и Triangle. В оба класса добавлены конструкторы, принимающие объект в качестве параметра.
// Передать ссылку на объект производного класса // переменной ссылки на объект базового класса.
using System;
class TwoDShape { double pri_width; double pri_height;
// Конструктор по умолчанию, public TwoDShape() {
Width = Height = 0.0;
}
// Конструктор для класса TwoDShape. public TwoDShape(double w, double h) {
Width = w;
Height = h;
}
// Сконструировать объект равной ширины и высоты, public TwoDShape(double х) {
Width = Height = x;
}
// Сконструировать копию объекта TwoDShape. public TwoDShape(TwoDShape ob) {
Width = ob.Width;
Height = ob.Height;
}
// Свойства ширины и высоты объекта, public double Width {
get { return pri_width; }
set { pri_width = value < 0 ? -value : value; }
}
get { return pri_height; }
set { pri_height = value < 0 ? -value : value; }
}
public void ShowDim() {
Console.WriteLine("Ширина и высота равны " +
Width + " и " + Height);
}
}
// Класс для треугольников, производный от класса TwoDShape. class Triangle : TwoDShape { string Style;
// Конструктор, используемый по умолчанию, public Triangle() {
Style = "null";
}
// Конструктор для класса Triangle.
public Triangle(string s, double w, double h) : base(w, h) { Style = s;
}
// Сконструировать равнобедренный треугольник, public Triangle(double x) : base (x) {
Style = "равнобедренный";
}
// Сконструировать копию объекта типа Triangle, public Triangle(Triangle ob) : base (ob) {
Style = ob.Style;
}
// Возвратить площадь треугольника, public double Area() {
return Width * Height / 2;
}
// Показать тип треугольника, public void ShowStyle() {
Console.WriteLine("Треугольник " + Style);
}
}
class Shapes7 {
static void Ma^n() {
Triangle tl = new Triangle("прямоугольный", 8.0, 12.0);
// Сделать копию объекта tl.
Triangle t2 = new Triangle ('t*L) ;
Console.WriteLine("Сведения об объекте tl: "); tl.ShowStyle();
tl.ShowDim();
Console.WriteLine ("Площадь равна " + tl.AreaO);
Console.WriteLine ();
Console.WriteLine("Сведения об объекте t2: "); t2.ShowStyle(); t2.ShowDim();
Console.WriteLine("Площадь равна " + t2.Area());
}
}
В представленном выше примере объект t2 конструируется из объекта tin поэтому подобен ему. Ниже приведен результат'выполнения кода из данного примера.
Сведения об объекте tl:
Треугольник прямоугольный Ширина и высота равны 8 и 12 Площадь равна 48
Сведения об объекте t2:
Треугольник прямоугольный Ширина и высота равны 8 и 12 Площадь равна 48
Обратите особое внимание на следующий конструктор класса Triangle:
public Triangle(Triangle ob) : base(ob) {
Читать дальше