1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 38
Текст из файла (страница 38)
Например,следующая версия класса Rect содержит метод enlarge(), который создает объектпрямоугольника как результат пропорционального увеличения (при заданномкоэффициенте увеличения) сторон вызывающего (этот метод) объекта прямоугольника.// Демонстрация возвращения методом объекта.using System;class Rect {int width;int height;public Rect(int w, int h) {width = w;height = h;}public int area() {return width * height;}Глава 8.
Подробнее о методах и классах199public void show() {Console.WriteLine(width + " " + height);}}/* Метод возвращает прямоугольник, который увеличен посравнению с вызывающим объектом прямоугольника сиспользованием заданного коэффициента увеличения. */public Rect enlarge(int factor) {return new Rect(width * factor, height * factor);}class RetObj {public static void Main() {Rect r1 = new Rect(4, 5);Console.Write("Размеры прямоугольника r1: ");r1.show();Console.WriteLine("Площадь прямоугольника r1: " +r1.area());Console.WriteLine();// Создаем прямоугольник, который вдвое больше// прямоугольника r1 .Rect r2 = r1.enlarge(2);Console.Write("Размеры прямоугольника r2: ");r2.show();}}Console.WriteLine("Площадь прямоугольника r2: " +r2.area());Вот результаты выполнения этой программы:Размеры прямоугольника r1: 4 5Площадь прямоугольника r1: 20Размеры прямоугольника r2: 8 10Площадь прямоугольника r2: 80В тех случаях, когда метод возвращает объект, существование этого объектапродолжается до тех пор, пока на него есть хотя бы одна ссылка.
И только когда на объектбольше нет ни одной ссылки, он подвергается утилизации, т.е. попадает в поле действияпроцесса сбора мусора. Таким образом, объект не будет разрушен только по причинезавершения метода, который его создал.Одним из применений классовых типов значений, возвращаемых методами, являетсягенератор объектов класса, или фабрика класса (class factory). “Фабрика” класса — этометод, который используется для построения объектов заданного класса. В определенныхслучаях пользователям некоторого класса нежелательно предоставлять доступ к.конструктору этого класса из соображений безопасности или по причине того, что созданиеобъектов зависит от неких внешних факторов. В таких случаях для построения объектов ииспользуется “фабрика” класса. Рассмотрим простой пример:// Использование "фабрики" класса.using System;200Часть I.
Язык C#class MyClass {int a, b; // закрытые члены// Создаем "фабрику" класса для класса MyClass.public MyClass factory(int i, int j) {MyClass t = new MyClass();t.a = i;t.b = j;}}return t; // Метод возвращает объект.public void show() {Console.WriteLine("а и b: " + a + " " + b);}class MakeObjects {public static void Main() {MyClass ob = new MyClass();int i, j;// Генерируем объекты с помощью "фабрики" класса.for(i=0, j=10; i < 10; i++, j--) {MyClass anotherOb = ob.factory(i, j);// Создаем// объект.anotherOb.show();}Console.WriteLine();}}Вот результаты выполнения этой программыа и b: 0 10а и b: 1 9а и b: 2 8а и b: 3 7а и b: 4 6а и b: 5 5а и b: 6 4а и b: 7 3а и b: 8 2а и b: 9 1Рассмотрим этот пример более внимательно.
В классе MyClass конструктор неопределен, поэтому доступен только конструктор, создаваемый средствами C# поумолчанию. Следовательно, установить значения членов класса а и b с помощьюконструктора невозможно. Однако создавать объекты с заданными значениями членов а иb способна “фабрика” класса, реализованная в виде метода factory(). Более того,поскольку члены а и b закрыты, использование метода factory() — единственныйспособ установки этих значений.В функции Main() создается объект ob класса MyClass, а затем в цикле forсоздается еще десять объектов. Приведем здесь строку кода, которая представляет собойосновной “конвейер” объектов.MyClass anotherOb = ob.factory(i, j); // создаем объектГлава 8. Подробнее о методах и классах201На каждой итерации цикла создается ссылочная переменная anotherOb, которойприсваивается ссылка на объект, сгенерированный “фабрикой” объектов.
В конце каждойитерации цикла ссылочная переменная anotherOb выходит из области видимости, иобъект, на который она ссылалась, утилизируется.Возвращение методами массивовПоскольку в C# массивы реализованы как объекты, метод может возвратить массив.(В этом еще одно отличие C# от языка C++, в котором не допускается, чтобы метод, илифункция, возвращал массив.) Например, в следующей программе метод findfactors()возвращает массив, который содержит множители аргумента, переданного этому методу.// Демонстрация возврата методом массива.using System;class Factor {/* Метод возвращает массив, содержащий множителипараметра num. После выполнения методаout-параметр numfactors будет содержать количествонайденных множителей. */public int[] findfactors(int num, out int numfactors) {int[] facts = new int[80]; // Размер 80 взят произвольно.int i, j;// Находим множители и помещаем их в массив facts.for(i=2, j=0; i < num/2 + 1; i++)if( (num%i)==0 ) {facts[j] = i;j++;}numfactors = j; return facts;}}class FindFactors {public static void Main() {Factor f = new Factor();int numfactors;int[] factors;factors = f.findfactors(1000, out numfactors);Console.WriteLine("Множители числа 1000: ");for(int i=0; i < numfactors; i++)Console.Write(factors[i] + " ");}}Console.WriteLine();Вот результаты выполнения этой программы:Множители числа 1000:2 4 5 8 10 20 25 40 50 100 125 200 250 500202Часть I.
Язык C#В классе Factor метод findfactors() объявляется следующим образом:public int[] findfactors(int num, out int numfactors) {Обратите внимание на то, как задан тип возвращаемого массива int. Этот синтаксисможно обобщить. Если вам нужно, чтобы метод возвращал массив, объявите его (метод)подобным образом, изменив при необходимости тип массива и размерность. Например, этаинструкция объявляет метод с именем someMeth(), который возвращает двумерныймассив double-значений.public double[,] someMeth() { // ...Перегрузка методовВ этом разделе мы узнаем об одной из самых удивительных возможностей языка C#— перегрузке методов.
В C# два или больше методов внутри одного класса могут иметьодинаковое имя, но при условии, что их параметры будут различными. Такую ситуациюназывают перегрузкой методов (method overloading), а методы, которые в нейзадействованы, — перегруженными (overloaded). Перегрузка методов — один из способовреализации полиморфизма в C#.В общем случае для создания перегрузки некоторого метода достаточно объявитьеще одну его версию. Об остальном позаботится компилятор. Но здесь необходимоотметить одно важное условие: все перегруженные методы должны иметь спискипараметров, которые отличаются по типу и/или количеству.
Методам для перегрузкинедостаточно отличаться лишь типами возвращаемых значений. Они должны отличатьсятипами или числом параметров. (Другими словами, тип возвращаемого значения необеспечивает достаточную информацию для C#, чтобы можно решить, какой именно методдолжен быть вызван.) Конечно, перегруженные методы могут отличаться и типамивозвращаемых значений. При вызове перегруженного метода выполняется та его версия,параметры которой совпадают (по типу и количеству) с заданными аргументами.Вот простой пример, иллюстрирующий перегрузку методов:// Демонстрация перегрузки методов.using System;class Overload {public void ovlDemo() {Console.WriteLine("Без параметров");}// Перегружаем метод ovlDemo() для одного// целочисленного параметра.public void ovlDemo(int a) {Console.WriteLine("Один параметр: " + a);}// Перегружаем метод ovlDemo() для двух// целочисленных параметров.public int ovlDemo(int a, int b) {Console.WriteLine("Два int-параметра: " + a + " " + b);return a + b;}// Перегружаем метод ovlDemo() для двухГлава 8.
Подробнее о методах и классах203// double-параметров.public double ovlDemo(double a, double b) {Console.WriteLine("Два double-параметра: " +a + " "+ b);return a + b;}}class OverloadDemo {public static void Main() {Overload ob = new Overload();int resI;double resD;// Вызываем все версии метода ovlDemo().ob.ovlDemo();Console.WriteLine();ob.ovlDemo(2);Console.WriteLine();resI = ob.ovlDemo(4, 6);Console.WriteLine("Результат вызова ob.ovlDemo(4, 6): "+ resI);Console.WriteLine();}}resD = ob.ovlDemo(1.1, 2.32);Console.WriteLine("Результат вызова ob.ovlDemo(1.1, 2.2): " + resD);Программа генерирует следующие результаты:Без параметровОдин параметр: 2Два int-параметра: 4 6Результат вызова ob.ovlDemo(4, 6): 10Два double-параметра: 1,1 2,32Результат вызова ob.ovlDemo(1.1, 2.2): 3,42Как видите, метод ovlDemo() перегружается четыре раза.
Первая версия вообще непринимает параметров, вторая принимает один целочисленный параметр, третья — двацелочисленных параметра, а четвертая — два double-параметра. Обратите внимание нато, что первые две версии метода ovlDemo() возвращают тип void, т.е. не возвращаютникакого значения, а вторые две возвращают значения соответствующих типов. Это вполнедопустимо, но, как уже разъяснялось, перегрузка методов не достигается различием тольков типе возвращаемого значения. Поэтому попытка использовать следующие две версииметода ovlDemo() приведет к ошибке:// Одно объявление метода ovlDemo(int) вполне допустимо.public void ovlDemo(int a) {Console.WriteLine("Один параметр: " + a);}204Часть I.
Язык C#// Ошибка! Два объявления метода ovlDemo(int) неприемлемы,// несмотря на то, что типы возвращаемых ими значений// разные.public int ovlDemo(int a) {Console.WriteLine("Один параметр: " + a);return a * a;}Как отмечено в комментариях, различие в типах значений, возвращаемых методами,является недостаточным фактором для обеспечения их перегрузки.Как указывалось в главе 3, в определенных пределах C# обеспечивает автоматическоепреобразование типов. Эта возможность преобразования типов применяется и к параметрамперегруженных методов. Рассмотрим, например, следующую программу./* Возможность автоматического преобразования типов может повлиятьна решение о перегрузке методов. */using System;class Overload2 {public void f(int x) {Console.WriteLine("Внутри метода f(int): " + x);}public void f(double x) {Console.WriteLine("Внутри метода f(double): " + x);}}class TypeConv {public static void Main() {Overload2 ob = new Overload2();int i = 10;double d = 10.1;byte b = 99;short s = 10;float f = 11.5F;ob.f(i); // Вызов метода ob.f(int).ob.f(d); // Вызов метода ob.f(double).ob.f(b); // Вызов метода ob.f(int) — выполняется// преобразование типов.ob.f(s); // Вызов метода ob.f(int) — выполняется// преобразование типов.}}ob.f(f); // Вызов метода ob.f(double) — выполняется// преобразование типов.Вот результаты выполнения этой программы:Внутри метода f(int): 10Внутри метода f(double): 10,1Внутри метода f(int): 99Внутри метода f(int): 10Внутри метода f(double): 11,5Глава 8.