
- •Глава 13. Включение, вложение и наследование классов
- •13.1. Включение объектов классов
- •13.2. Вложение классов
- •13.3. Наследование классов
- •13.4. Доступность членов класса при наследовании
- •13.5. Методы при наследовании
- •13.6. Абстрактные методы и абстрактные классы.
- •13.7. Опечатанные классы и методы
- •13.8. Применение абстрактых классов
Глава 13. Включение, вложение и наследование классов
13.1. Включение объектов классов
В соответствии с основной задачей, решаемой при проектировании программы, входящие в нее классы могут находиться в разных отношениях. Наиболее простое - отношение независимости классов, то есть независимости порождаемых ими объектов. Более сложное - отношение включения, для которого используют названия "имеет" (has-a) и "включает" (is-part-of).
В теории объектно-ориентированного анализа различают две формы отношения включения – композицию и агрегацию.
При отношении композиции объекты одного класса или нескольких разных классов входят как поля в объект другого (включающего) класса. Таким образом, включенные объекты не существуют без включающего их объекта.
При отношении агрегации объект одного класса объединяет уже существующие объекты других классов. То есть и включающий объект и включаемые в него объекты существуют в некотором смысле самостоятельно. При уничтожении включающего объекта входившие в него объекты сохраняются.
Рассмотрим на примерах особенности реализации на языке С# отношений композиции и агрегации.
Определим (программа 13_01.cs) класс "точка на плоскости": class Point
class Point
{
double x, y;
public double X { get { return x; } set { x = value; } }
public double Y { get { return y; } set { y = value; } }
}
В классе закрытые поля double x, у определяют координаты точки. Свойства X и Y обеспечивают удобный доступ к координатам точки, представленной объектом класса Point. В классе Point нет явно определенного конструктора и компилятор добавляет открытый конструктор без параметров, при использовании которого координаты создаваемой точки по умолчанию получают нулевые значения.
Объекты класса Point можно по-разному включать в более сложные классы. Возьмем в качестве такого включающего класса класс Circle, объект которого представляет "окружность на плоскости". Объект класса Point (точку) будем использовать в качестве центра окружности.
Начнем с композиции классов и, отложив объяснения, дадим такое определение класса:
class Circle
{ // Закрытые поля:
double rad; // радиус окружности
Point centre = new Point(); // центр окружности
// свойство для радиуса окружности:
public double Rad { get { return rad; } set { rad = value; } }
// свойство для получения значения длины окружности:
public double Len { get { return 2*rad*Math.PI; } }
// свойство для центра окружности:
public Point Centre { get { return centre; } set { centre = value; } }
public void display()
{
Console.WriteLine("Centre: X={0}, Y={1}; Radius={2}, Length={3, 6:f2}", centre.X, centre.Y, this.rad, Len);
}
}
В классе Circle два закрытых поля: double rad - радиус окружности и Point centre - ссылка на объект класса Point. Для инициализации этой ссылки используется выражение с операцией new, в котором выполняется явное обращение к конструктору класса Point. Тем самым при создании каждого объекта "окружность" всегда создается в виде его поля объект "точка", определяющий центр окружности.
Три открытых свойства обеспечивают доступ к характеристикам объекта-окружности: Rad - радиус окружности, Len - длина окружности, Centre -центр окружности.
В классе определен открытый метод display(), выводящий координаты центра и значения других характеристик объекта, представляющего окружность.
Так как в классе Circle нет явно определенных конструкторов, то неявно создается конструктор без параметров и поля определяемого с его помощью объекта получают значения по умолчанию.
В следующей программе создан объект класса Circle. Затем с помощью свойств классов Circle и Point изменены значения его полей. Метод display() выводит сведения о характеристиках объекта,
public static void Main()
{
Circle rim = new Circle();
rim.Centre.X = 10;
rim.Centre.Y = 20;
rim.Rad = 3.0;
rim.display();
}
Результат выполнения программы:
Centre: X=10, Y=20; Radius=3, Length= 18,85
Основное, на что следует обратить внимание, - в программе нет отдельно существующего объекта класса Point. Именно это является основным признаком композиции классов. Объект класса Point явно создаётся только при создании объекта класса Circle.
Не изменяя класс Point, можно следующим образом построить класс "окружность на плоскости", используя агрегацию классов (программа 13_2.cs):
class Circle
{ // Закрытые поля:
double rad; // радиус окружности
Point centre; // ссылка без инициализации
public Circle(Point p, double rd) // конструктор
{
centre = p;
rad = rd;
}
public double Rad { get { return rad; } set { rad = value; } }
public double Len { get { return 2 * rad * Math.PI; } }
public Point Centre { get { return centre; } set { centre = value; } }
public void display()
{
Console.WriteLine("Centre: X={0}, Y={1}; Radius={2}, Length={3, 6:f2}", centre.X, centre.Y, this.rad, Len);
}
}
В тексте нового класса Circle показаны полностью только объявления полей и конструктор, первый параметр которого - ссылка на объект класса Point. Свойства и метод display() остались без изменений.
При таком измененном определении класса Circle для создания его объекта необходимо, чтобы уже существовал объект класса Point, с помощью которого в объекте будет определено значение поля centre.
Диаграмма классов, находящихся в отношении агрегации, (см. рис. 13.2), практически та же, что и диаграмма композиции. Только в классе Circle явно присутствует конструктор общего вида.
В следующей программе (в методе Main) создан объект класса Point. Затем с помощью свойств X и Y изменены значения его полей. На основе этого объекта конструктор класса Circle формирует объект "окружность на плоскости". Метод display() выводит сведения о характеристиках построенного объекта,
public static void Main()
{
Point pt = new Point();
pt.X = 10;
pt.Y = 20;
Circle rim = new Circle(pt, 10);
rim.display();
}
Результат выполнения программы:
Centre: X=10, Y=20; Radius=10, Length=62,83
В отличие от композиции при агрегации в классе Circle нет явной инициализации поля centre. Для обеспечения включения объекта класса Point в объект класса Circle в классе Circle явно определен конструктор, одним из параметров которого служит ссылка на объект класса Point. В теле конструктора значение этой ссылки присваивается полю centre класса Circle.