Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по ООП (язык C#).pdf
Скачиваний:
190
Добавлен:
16.05.2015
Размер:
1.54 Mб
Скачать

Чернов Э. А.

- 60 -

Лекции по языку C# v 2.3

Ниже приведен вариант выполнения программы.

Уровень protected обеспечивает доступ только из производного класса в базовый. В примере основная программа (Main) входит в состав постороннего класса, который не является ни базовым, ни производным классом, поэтому для доступа к подпрограммам rest из основной программы требуется уровень public.

Виртуальные функции

Виртуальная функция определяется внутри базового класса и может быть переоп-

ределена в производном классе. Ключевое слово virtual указывает на виртуальную функцию, например:

public virtual void fun ( )

{

// Операторы реализации функции

}

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

Ниже приведена программа, состоящая из базового и двух производных классов. В задаче определяется сопротивление цепи, состоящей из двух резисторов. Резисторы могут быть соединены последовательно или параллельно. При последовательном соединении сопротивления суммируются, при параллельном соединении итоговое сопротивление равно сумме проводимостей:

Для двух резисторов общее сопротивление равно произведению исходных сопротивлений, которое делится на их сумму.

class Res // Базовый класс

 

{

 

protected double res1, res2;

// Сопротивления

Чернов Э. А.

- 61 -

Лекции по языку C# v 2.3

public Res() { res1 = res2 = 0.0; } // Конструктор без параметров public virtual double get_chain_resist()

{

return 0.0; // Эта функция должна что-нибудь возвращать

}

//Свойство для первого резистора public double R1

{

get { return res1; } set { res1 = value; }

}

//Свойство для второго резистора public double R2

{

get { return res2; } set { res2 = value; }

}

}

//Этот класс определяет сопротивление цепи при параллельном

//соединении резисторов */

class Paral : Res

{

//Конструктор принимает 2 параметра и передает их в конструктор

//с параметрами базового класса

public Paral(double r1, double r2): base()

{

this.res1 = r1; this.res2 = r2;

}

public override double get_chain_resist()

{

return R1*R2/(R1 + R2);

}

}

//Этот класс определяет сопротивление цепи при

//последовательном соединении резисторов class Sequent : Res

{

//Конструктор c двумя параметрами и наследник пустого

//конструктора базового класса

public Sequent(double r1, double r2) : base()//

{

this.res1 = r1; this.res2 = r2;

}

public override double get_chain_resist()

{

return R1 + R2; // Итоговое сопротивление

}

}

class Program

{

Чернов Э. А.

- 62 -

Лекции по языку C# v 2.3

static void Main(string[] args)

{

double inr1, inr2;

Console.WriteLine("\n Введите значения сопротивлений \n"); inr1 = double.Parse(Console.ReadLine());

inr2 = double.Parse(Console.ReadLine()); //Объявление базового класса

Res r = new Res ();

// Объявление производного класса для последовательного соединения r = new Sequent(inr1, inr2);

Console.WriteLine(" R при последовательном соединении = " + r.get_chain_resist());

// Объявление производного класса для параллельного соединения r = new Paral(inr1, inr2);

Console.WriteLine(" R при параллельном соединении = " + r.get_chain_resist());

Console.ReadKey(); // Для останова экрана пользователя

}

}

Пример выполнения программы:

В приведенном выше примере виртуальная функция базового класса не имеет выполняемых действий. Полезные операции она выполняет только после переопределения в производных классах. Это распространенная ситуация, при которой базовый класс содержит только набор пустых функций, которые должны переопределяться в производных классах.

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

Для иллюстрации сказанного в приведенной выше программе для получения значений сопротивлений для разных видов соединения применяется одна и та же форма вызова:

r.get_chain_resist(), где r объект базового класса.

Если виртуальная функция в базовом классе не выполняет никаких действий, ее можно объявить абстрактной, чтобы подчеркнуть, что она пустая. Для приведенного выше примера объявление будет иметь вид:

public abstract double get_chain_resist();

Чернов Э. А.

- 63 -

Лекции по языку C# v 2.3

Если класс имеет хотя бы одну виртуальную функцию, то он называется абстрактным.

Ниже приведена программа из книги Г. Шилдта «Полный справочник по языку C#», в которой рассматривается несколько производных классов. Для этой программе выполнена косметическая правка

class TwoDShape

{

double pri_width; double pri_height;

public TwoDShape() // Конструктор по умолчанию,

{

Width = Height = 0.0; // параметры конструктора определены в свойствах name = "null";

}

// Конструктор с параметрами.

public TwoDShape(double w, double h, string n)

{

Width = w;

Height = h; name = n;

}

//Конструктор объекта с одинаковой шириной и высотой. public TwoDShape(double x, string n)

{

Width = Height = x; name = n;

}

//Конструктор копирования для объекта TwoDShape. public TwoDShape(TwoDShape ob)

{

Width = ob.Width; Height = ob.Height; name = ob.name;

}

//Свойства ширины и высоты объекта,

public double Width

{

get { return pri_width; }

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

}

public double Height

{

get { return pri_height; }

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

}

public string name { get; set; } // Свойство для названия public void ShowDim()

{

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

}

public virtual double Area()

{

return 0.0;

Чернов Э. А.

- 64 -

Лекции по языку C# v 2.3

}

}

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

{

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;

}

//Переопределить метод Area() для класса Triangle, public override double Area() { return Width * Height / 2; } public void ShowStyle() // Показать тип треугольника

{

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

}

}

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

{

// Конструктор для класса Rectangle,

public Rectangle(double w, double h) : base(w, h, "прямоугольник") { } // Конструктор для квадрата

public Rectangle(double x) : base(x, "прямоугольник") { }

//Конструктор копирования объекта типа Rectangle, public Rectangle(Rectangle ob) : base(ob) { }

//Возвратить логическое значение true, если квадрат. public bool IsSquare()

{

if (Width == Height) return true; return false;

}

//Переопределить метод Area() для класса Rectangle, public override double Area()

{

return Width * Height;

}