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

8.2 Передача объектов методам по ссылке

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

Листинг 8.4

// Пример передачи объектов методам по ссылке.

using System;

class MyClass

{

int alpha, beta;

public MyClass(int i, int j)

{

alpha = i;

beta = j;

}

// Возвратить значение true, параметр ob

// имеет те же значения, что и вызывающий объект.

public bool SameAs(MyClass ob)

{

if((ob.alpha == alpha) & (ob.beta == beta))

return true;

else return false;

}

// Создать копию объекта ob.

public void Copy(MyClass ob)

{

alpha = ob.alpha;

beta = ob.beta;

}

public void Show() {

Console.WriteLine("alpha: {0}, beta: {1}",

alpha, beta);

}

}

class PassOb

{

static void Main()

{

MyClass ob1 = new MyClass(4, 5);

MyClass ob2 = new MyClass(6, 7);

Console.Write("ob1: ");

ob1.Show();

Console.Write("ob2: ");

ob2.Show();

if(ob1.SameAs(ob2))

Console.WriteLine("ob1 и ob2 имеют одинаковые значения.");

else

Console.WriteLine("ob1 и ob2 имеют разные значения.");

Console.WriteLine();

// А теперь сделать объект ob1 копией объекта ob2.

ob1.Copy(ob2);

Console.Write("ob1 после копирования: ");

ob1.Show();

if(ob1.SameAs(ob2))

Console.WriteLine("ob1 и ob2 имеют одинаковые значения.");

else

Console.WriteLine("ob1 и ob2 имеют разные значения.");

}

}

Выполнение этой программы дает следующий результат.

ob1: alpha: 4, beta: 5

ob2: alpha: 6, beta: 7

ob1 и ob2 имеют разные значения

ob1 после копирования: alpha: 6, beta: 7

ob1 и ob2 имеют одинаковые значения

Каждый из методов SameAs()и Сору() в приведенной выше программе получа­ет ссылку на объект типа MyClass в качестве аргумента. Метод SameAs() сравнивает значения переменных экземпляра alpha и beta в вызывающем объекте со значени­ями аналогичных переменных в объекте, передаваемом посредством параметра ob. Данный метод возвращает логическое значение true только в том случае, если оба объекта имеют одинаковые значения этих переменных экземпляра. А метод Сору() присваивает значения переменных alpha и beta из объекта, передаваемого по ссылке посредством параметра ob, переменным alpha и beta из вызывающего объекта. Как показывает данный пример, с точки зрения синтаксиса объекты передаются методам по ссылке таким же образом, как и значения обычных типов.

8.2.1 Способы передачи аргументов методу

Как показывает приведенный выше пример, передача объекта методу по ссылке делается достаточно просто. Но в этом примере показаны не все нюансы данного про­цесса. В некоторых случаях последствия передачи объекта по ссылке будут отличаться от тех результатов, к которым приводит передача значения обычного типа. Для выяс­нения причин этих отличий рассмотрим два способа передачи аргументов методу.

Первым способом является вызов по значению. В этом случае значение аргумента копируется в формальный параметр метода. Следовательно, изменения, вносимые в параметр метода, не оказывают никакого влияния на аргумент, используемый для вы­зова. А вторым способом передачи аргумента является вызов по ссылке. В данном случае параметру метода передается ссылка на аргумент, а не значение аргумента. В методе эта ссылка используется для доступа к конкретному аргументу, указываемому при вы­зове. Это означает, что изменения, вносимые в параметр, будут оказывать влияние на аргумент, используемый для вызова метода.

По умолчанию в С# используется вызов по значению, а это означает, что копия ар­гумента создается и затем передается принимающему параметру. Следовательно, при передаче значения обычного типа, например int или double, все, что происходит с параметром, принимающим аргумент, не оказывает никакого влияния за пределами метода. В качестве примера рассмотрим следующую программу.

Листинг 8.5

// Передача аргументов обычных типов по значению.

using System;

class Test

{

/* Этот метод не оказывает никакого влияния н

на аргументы, используемые для его вызова. */

public void NoChange(int i, int j) {

i = i + j;

j = -j;

}

}

class CallByValue {

static void Main() {

Test ob = new Test();

int a = 15, b = 20;

Console.WriteLine("a и b до вызова: " +

a + " " + b);

ob.NoChange(a, b);

Console.WriteLine("a и b после вызова: " +

a + " " + b);

}

}

Вот какой результат дает выполнение этой программы.

а и b до вызова: 15 2 0

а и b после вызова: 15 2 0

Как видите, операции, выполняемые в методе NoChange(), не оказывают никакого влияния на значения аргументов а и b, используемых для вызова данного метода. Это опять же объясняется тем, что параметрам i и j переданы копии значений аргументов а и b, а сами аргументы а и b совершенно не зависят от параметров i и j. В частности, присваивание параметру i нового значения не будет оказывать никакого влияния на аргумент а.

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

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

Листинг 8.6

// Передача объектов по ссылке.

using System;

class Test

{

public int a, b;

public Test(int i, int j)

{

a = i;

b = j;

}

/* Передать объект. Теперь переменные ob.a и ob.b из объекта,

Используемого в вызове метода, будут изменены. */

public void Change(Test ob) {

ob.a = ob.a + ob.b;

ob.b = -ob.b;

}

}

class CallByRef {

static void Main() {

Test ob = new Test(15, 20);

Console.WriteLine("ob.a и ob.b до вызова: " +

ob.a + " " + ob.b);

ob.Change(ob);

Console.WriteLine("ob.a и ob.b после вызова: " +

ob.a + " " + ob.b);

}

}

Выполнение этой программы дает следующий результат.

ob.a и ob.b до вызова: 15 20

ob.a и ob.b после вызова: 35 -20

Как видите, действия в методе Change() оказали в данном случае влияние на объект, использовавшийся в качестве аргумента.

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