Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Наследование.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
135.39 Кб
Скачать

11.2 Доступ к членам класса и наследование

Члены класса зачастую объявляются закрытыми, чтобы исключить их несанкционированное или незаконное использование. Но наследование класса не отменяет ограничения, накладываемые на доступ к закрытым членам класса. Поэтому если в производный класс и входят все члены его базового класса, в нем все равно оказываются недоступными те члены базового класса, которые являются закры­тыми. Так, если сделать закрытыми переменные класса TwoDShape, они станут недо­ступными в классе Triangle, как показано ниже.

Листинг 11.4

// Доступ к закрытым членам класса не наследуется.

// Этот пример кода не подлежит компиляции.

using System;

// Класс для двумерных объектов.

class TwoDShape

{

double Width; // теперь это закрытая переменная

double Height; // теперь это закрытая переменная

public void ShowDim()

{

Console.WriteLine("Ширина и высота равны " +

Width + " и " + Height);

}

}

// Класс Triangle производный от класса TwoDShape.

class Triangle : TwoDShape

{

public string Style; // тип треугольника

// Возвратить площадь треугольника.

public double Area()

{

return Width * Height / 2; // Ошибка. Доступ к закрытому

// члену класса запрещен

}

// Показать тип треугольника.

public void ShowStyle() {

Console.WriteLine("Треугольник " + Style);

}

}

Класс Triangle не будет компилироваться, потому что обращаться к перемен­ным Width и Height из метода Area() запрещено. А поскольку переменные Width и Height теперь являются закрытыми, то они доступны только для других членов своего класса, но не для членов производных классов.

Закрытый член класса остается закрытым в своем классе. Он не доступен из кода за пределами своего класса, включая и производные классы.

На первый взгляд, ограничение на доступ к частным членам базового класса из про­изводного класса кажется трудно преодолимым, поскольку оно не дает во многих слу­чаях возможности пользоваться частными членами этого класса. Но на самом деле это не так. Для преодоления данного ограничения в С# предусмотрены разные способы. Один из них состоит в использовании защищенных (protected) членов класса, рас­сматриваемых в следующем разделе, а второй  в применении открытых свойств для доступа к закрытым данным.

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

Ниже приведен вариант класса TwoDShape, в котором переменные Width и Height превращены в свойства. По ходу дела в этом классе выполняется проверка: являются ли положительными значения свойств Width и Height. Это дает, например, возможность указывать свойства Width и Height в качестве координат формы в любом квадранте прямоугольной системы координат, не получая заранее их абсолютные значения.

Листинг 11.5

// Использовать открытые свойства для установки и

// получения значений закрытых членов класса.

using System;

// Класс для двумерных объектов.

class TwoDShape

{

double width; // это закрытая переменная

double height; // это закрытая переменная

// Свойства ширины и высоты двумерного объекта.

public double Width

{

get { return width; }

set { width = value < 0 ? -value : value; }

}

public double Height

{

get { return height; }

set { height = value < 0 ? -value : value; }

}

public void ShowDim()

{

Console.WriteLine("Ширина и высота равны " +

Width + " и " + Height);

}

}

// Класс для треугольников, производный от класса TwoDShape.

class Triangle : TwoDShape

{

public string Style; // тип треугольника

// Возвратить площадь треугольника.

public double Area()

{

return Width * Height / 2;

}

// Показать тип треугольника.

public void ShowStyle()

{

Console.WriteLine("Triangle is " + Style);

}

}

class Shapes2 {

static void Main()

{

Triangle t1 = new Triangle();

Triangle t2 = new Triangle();

t1.Width = 4.0;

t1.Height = 4.0;

t1.Style = "равнобедренный";

t2.Width = 8.0;

t2.Height = 12.0;

t2.Style = "прямоугольный";

Console.WriteLine("Сведения об объекте t1: ");

t1.ShowStyle();

t1.ShowDim();

Console.WriteLine("Площадь равна " + t1.Area());

Console.WriteLine();

Console.WriteLine("Сведения об объекте t2: ");

t2.ShowStyle();

t2.ShowDim();

Console.WriteLine("Площадь равна " + t2.Area());

}

}

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

Базовый и производный классы иногда еще называют суперклассом и подклассом соответственно. Эти термины происходят из практики программирования на Java. То, что в Java называется суперклассом, в С# обозначается как базовый класс. А то, что в Java называется подклассом, в С# обозначается как производный класс. Оба ряда тер­минов часто применяются к классу в обоих языках программирования, но в этой книге по-прежнему употребляются общепринятые в С# термины базового и производного классов, которые принято употреблять и в С++.