- •8 Подробнее о методах и классах
- •8.1 Управление доступом к членам класса
- •8.1.1 Модификаторы доступа
- •8.1.2 Организация закрытого и открытого доступа
- •8.1.3 Практический пример организации управления доступом
- •8.2 Передача объектов методам по ссылке
- •8.2.1 Способы передачи аргументов методу
- •8.3 Использование модификаторов параметров ref и out
- •8.3.1 Использование модификатора параметра ref
- •8.3.2 Использование модификатора параметра out
- •8.3.3 Использование модификаторов ref и out для ссылок на объекты
- •8.4 Использование переменного числа аргументов
- •8.5 Возврат объектов из методов
- •8.5.1 Возврат массива из метода
- •8.6 Перегрузка методов
- •8.7 Перегрузка конструкторов
- •8.7.1 Вызов перегружаемого конструктора с помощью ключевого
- •8.8 Инициализаторы объектов
- •8.9 Необязательные аргументы
- •8.9.1 Необязательные аргументы и перегрузка методов
- •8.9.2 Необязательные аргументы и неоднозначность
- •8.9.3 Практический пример использования необязательных аргументов
- •8.10 Именованные аргументы
- •8.11 Метод Main ()
- •8.11. 1 Возврат значений из метода Main()
- •8.11.2 Передача аргументов методу Main()
- •8.12 Рекурсия
- •8.13 Применение ключевого слова static
- •8.13.1 Статические конструкторы
- •8.14 Статические классы
8.7 Перегрузка конструкторов
Как и методы, конструкторы также могут перегружаться. Это дает возможность конструировать объекты самыми разными способами. В качестве примера рассмотрим следующую программу.
Листинг 8.20
// Продемонстрировать перегрузку конструктора.
using System;
class MyClass
{
public int x;
public MyClass()
{
Console.WriteLine("В конструкторе MyClass().");
x = 0;
}
public MyClass(int i)
{
Console.WriteLine("В конструкторе MyClass(int).");
x = i;
}
public MyClass(double d)
{
Console.WriteLine("В конструкторе MyClass(double).");
x = (int) d;
}
public MyClass(int i, int j)
{
Console.WriteLine("В конструкторе MyClass(int, int).");
x = i * j;
}
}
class OverloadConsDemo
{
static void Main()
{
MyClass t1 = new MyClass();
MyClass t2 = new MyClass(88);
MyClass t3 = new MyClass(17.23);
MyClass t4 = new MyClass(2, 4);
Console.WriteLine("t1.x: " + t1.x);
Console.WriteLine("t2.x: " + t2.x);
Console.WriteLine("t3.x: " + t3.x);
Console.WriteLine("t4.x: " + t4.x);
}
}
При выполнении этой программы получается следующий результат.
В конструкторе MyClass().
В конструкторе MyClass (int).
В конструкторе MyClass(double).
В конструкторе MyClass (int, int).
tl.x: 0
t2.x: 88
t3.x: 17
t4.x: 8
В данном примере конструктор MyClass() перегружается четыре раза, всякий раз конструируя объект по-разному. Подходящий конструктор вызывается каждый раз, исходя из аргументов, указываемых при выполнении оператора new. Перегрузка конструктора класса предоставляет пользователю этого класса дополнительные преимущества в конструировании объектов.
Одна из самых распространенных причин для перегрузки конструкторов заключается в необходимости предоставить возможность одним объектам инициализировать другие. В качестве примера ниже приведен усовершенствованный вариант разработанного ранее класса Stack, позволяющий конструировать один стек из другого.
Листинг 8.21
// Класс для хранения символов в стеке.
using System;
class Stack
{
// Эти члены класса являются закрытыми.
char[] stck; // массив, содержащий стек
int tos; // индекс вершины стека
// Сконструировать пустой объект класса Stack
// по заданному размеру стека.
public Stack(int size)
{
stck = new char[size]; // распределить память для стека
tos = 0;
}
// Сконструировать объект класса Stack из существующего стека.
public Stack(Stack ob) {
// Распределить память для стека.
stck = new char[ob.stck.Length];
// Скопировать элементы в новый стек.
for(int i=0; i < ob.tos; i++)
stck[i] = ob.stck[i];
// Установить переменную tos для нового стека.
tos = ob.tos;
}
// Поместить символы в стек.
public void Push(char ch
{
if(tos==stck.Length) {
Console.WriteLine(" – Стек заполнен.");
return;
}
stck[tos] = ch;
tos++;
}
// Извлечь символ из стека.
public char Pop()
{
if(tos==0) {
Console.WriteLine(" – Стек пуст.");
return (char) 0;
}
tos--;
return stck[tos];
}
// Возвратить значение true, если заполнен.
public bool IsFull()
{
return tos==stck.Length;
}
// Возвратить значение true, если стек пуст.
public bool IsEmpty() {
return tos==0;
}
// Возвратить общую емкость стека.
public int Capacity() {
return stck.Length;
}
// Возвратить количество объектов, находящихся
// в настоящий момент в стеке.
public int GetNum() {
return tos;
}
}
// Продемонстрировать применение класса Stack.
class StackDemo
{
static void Main()
{
Stack stk1 = new Stack(10);
char ch;
int i;
// Поместить ряд символов в стек stk1.
Console.WriteLine("Поместить симвоы A-J в стек stk1.");
for(i=0; !stk1.IsFull(); i++)
stk1.Push((char) ('A' + i));
// Создать копию стека stck1.
Stack stk2 = new Stack(stk1);
// Вывести содержимое стека stk1.
Console.Write("Содержимое стека stk1: ");
while( !stk1.IsEmpty() ) {
ch = stk1.Pop();
Console.Write(ch);
}
Console.WriteLine();
Console.Write("Содержимое стека stk2: ");
while ( !stk2.IsEmpty() ) {
ch = stk2.Pop();
Console.Write(ch);
}
Console.WriteLine("\n");
}
}
Результат выполнения этой программы приведен ниже.
Поместить символы A-J в стек stkl.
Содержимое стека stkl: JIHGFEDCBA
Содержимое стека stk2: JIHGFEDCBA
В классе StackDemo сначала конструируется первый стек (stkl), заполняемый символами. Затем этот стек используется, для конструирования второго стека (stk2). Это приводит к выполнению следующего конструктора класса Stack.
// Сконструировать объект класса Stack из существующего стека.
public Stack(Stack ob)
{
// Распределить память для стека.
stck = new char[ob.stck.Length];
// Скопировать элементы в новый стек.
for (int i=0; i < ob.tos; i++)
stck[i] = ob.stck[i];
// Установить переменйую tos для нового стека.
tos = ob.tos;
}
В этом конструкторе сначала распределяется достаточный объем памяти для массива, чтобы хранить в нем элементы стека, передаваемого в качестве аргумента ob. Затем содержимое массива, образующего стек ob, копируется в новый массив, после чего соответственно устанавливается переменная tos, содержащая индекс вершины стека. По завершении работы конструктора новый и исходный стеки существуют как отдельные, хотя и одинаковые объекты.
