Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ИДПО_ИИИС / Лекция 5.docx
Скачиваний:
67
Добавлен:
19.05.2015
Размер:
366.51 Кб
Скачать

Вынесение класса с точкой входа в отдельный файл

Мы в данном примере нехорошо поступили (ну, почти нехорошо), потому что принято каждый класс размещать в отдельном файле с названием, обычно совпадающем с именем класса. Исправим это.

  • Выполните команду Add Class в меню Project оболочки

  • Заполните окно мастера так

  • После нажатия кнопки Open мастер создаст новый файл с именем HelloApp.cs. Перенесите класс HelloApp из файла HelloClass в новый файл, при этом не забудьте изменить пространство имен на прежнее ConsoleApp. Не забудьте удалить код перенесенного класса HelloApp в прежнем файле HelloClass.cs. Окончательно новый файл должен выглядеть так

using System;

namespace ConsoleApp

{

class HelloApp

{

// Точка входа в программу

static void Main(string[] args)

{

// Создаем два объекта-экземпляра класса

HelloClass ob1 = new HelloClass(); // Вызов конструктора по умолчанию

Console.WriteLine("ob1: x = {0};

y = {1} \n", ob1.GetX(), ob1.GetY());

HelloClass ob2 = new HelloClass(10, 15); // Вызов общего конструктора

Console.WriteLine("ob2: x = {0};

y = {1}", ob2.GetX(), ob2.GetY());

while(true);

}

}

}

Листинг 8 . Перенос класса с функцией Main() в отдельный файл HelloApp.cs

  • Постройте приложение и убедитесь, что выходные результаты остались прежними

Тот же результат после переноса класса с функцией Main() в отдельный файл

Конструктор по умолчанию

ob1: x = 0; y = 0

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

ob2: x = 10; y = 15

Инициализация членов без конструктора

В C++ в классе можно простые переменные только объявлять, а инициализировать их нужно в конструкторе или устанавливать путем присваивания функциями Set() из клиента. В C# такое ограничение отсутствует и данные-члены класса можно инициализировать при их объявлении в классе. Примеры

class Text

{

private int MyInt = 90;

private string MyString = "My initial value";

private HotRod viper = new HotRod(200, "Chucky", Color.Red);

.............................................................

}

  • Измените код класса HelloClass нашего примера так, как показано ниже

using System;

namespace ConsoleApp

{

class HelloClass

{

// Внутренние переменные

private int x = 100, y = 150;

// Конструкторы

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

{

Console.WriteLine("Конструктор по умолчанию");

}

public HelloClass(int a, int b) // Конструктор с параметрами

{

Console.WriteLine("Конструктор с параметрами");

x = a;

y = b;

}

// Сервисы класса

public int GetX(){return x;}

public int GetY(){return y;}

}

}

Листинг 9 . Инициализация данных без конструктора

  • После построения проекта получим результат

Результат после прямой инициализации данных

Конструктор по умолчанию

ob1: x = 100; y = 150

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

ob2: x = 10; y = 15

Важное замечание

Отметим, что подобная прямая инициализация членов-данных в структурах недопустима. Перегрузка конструктора по умолчанию в структурах тоже недопустима.

Типы данных в c#

В C# различают структурные типы ( reference-based ) и ссылочные ( value-based ). Переменная структурного типа представляет закрепленное за ней само значение оперативной памяти. Переменная ссылочного типа содержит лишь адрес области оперативной памяти с размещаемым в этой области значением. Все структурные переменные размещаются на стеке, а ссылочные - на управляемой куче ( managed heap ). К структурным типам относятся перечисления и структуры, а к ссылочным - классы, массивы, указатели, интерфейсы.

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

  • Создайте консольное приложение C# или модифицируйте уже созданное. Заполните файл с точкой входа следующим кодом

using System;

namespace Test

{

struct FOO

{

public int x, y;

}

class ValRefClass

{

static void Main(string[] args)

{

// Создаем объект на стеке

// При создании структуры с конструктором по умолчанию

// ключевое слово new является необязательным,

// а можно просто FOO f1;

FOO f1 = new FOO();

f1.x = 100;

f1.y = 100;

// Создается объект на стеке без ключевого слова new

// и осуществляется побитовое копирование в другую память

FOO f2 = f1;

// Вывод до изменения

Console.WriteLine("Содержимое объектов

f1 и f2 до изменения");

Console.WriteLine("Объект f1: x={0};

y={1}", f1.x, f1.y);

Console.WriteLine("Объект f2: x={0};

y={1}", f2.x, f2.y);

// Внесение изменений

f1.x = 1; f1.y = 2; f2.x = 3; f2.y = 4;

// Вывод после изменения

Console.WriteLine("\nСодержимое объектов

f1 и f2 после изменения");

Console.WriteLine("Объект f1: x={0};

y={1}", f1.x, f1.y);

Console.WriteLine("Объект f2: x={0};

y={1}", f2.x, f2.y);

while(true);

}

}

}

Листинг 10 . Код для переменных структурного типа

Результаты экрана

Содержимое объектов f1 и f2 до изменения

Объект f1: x=100; y=100

Объект f2: x=100; y=100

Содержимое объектов f1 и f2 после изменения

Объект f1: x=1; y=2

Объект f2: x=3; y=4

  • Измените в исходном коде для типа FOO ключевое слово struct на class, тем самым сразу получим ссылочный тип. Запустите программу - получится результат

using System;

namespace Test

{

class FOO

{

public int x, y;

}

class ValRefClass

{

static void Main(string[] args)

{

// Создаем объект на куче

// Теперь слово new является обязательным, а также

// обазательны круглые скобки конструктора по умолчанию

FOO f1 = new FOO();

f1.x = 100;

f1.y = 100;

// Создается не объект, а ссылку, и после копирования

// адреса получаем псевдоним на ту же область памяти

FOO f2 = f1;

// Вывод до изменения

Console.WriteLine("Содержимое объектов f1 и

f2 до изменения");

Console.WriteLine("Объект f1: x={0};

y={1}", f1.x, f1.y);

Console.WriteLine("Объект f2: x={0};

y={1}", f2.x, f2.y);

// Внесение изменений

f1.x = 1; f1.y = 2; f2.x = 3; f2.y = 4;

// Вывод после изменения

Console.WriteLine("\nСодержимое объектов f1 и

f2 после изменения");

Console.WriteLine("Объект f1: x={0};

y={1}", f1.x, f1.y);

Console.WriteLine("Объект f2: x={0};

y={1}", f2.x, f2.y);

while(true);

}

}

}

Листинг 11 . Код для переменных ссылочного типа

Результаты экрана

Содержимое объектов f1 и f2 до изменения

Объект f1: x=100; y=100

Объект f2: x=100; y=100

Содержимое объектов f1 и f2 после изменения

Объект f1: x=3; y=4

Объект f2: x=3; y=4

Здесь мы видим, что в обоих случаях мы изменяли один и тот же объект, который и сохранил последние значения. Теперь f1 и f2 - не более чем ссылки на один и тот же диапазон памяти в области управляемой кучи.

Для того, чтобы объекты, адресуемые переменными f1 и f2, занимали разные области памяти, нужно запросить память у операционной системы для каждого из них и сохранить возвращенные адреса в этих переменных.

Следующий код и полученный результат иллюстрируют сказанное

using System;

namespace Test

{

class FOO

{

public int x, y;

}

class ValRefClass

{

static void Main(string[] args)

{

// Создаем первый объект на куче

FOO f1 = new FOO();

f1.x = 100;

f1.y = 100;

// Создается второй объект на куче

FOO f2 = new FOO();

f2.x = 100;

f2.y = 100;

// Вывод до изменения

Console.WriteLine("Содержимое объектов f1 и

f2 до изменения");

Console.WriteLine("Объект f1: x={0};

y={1}", f1.x, f1.y);

Console.WriteLine("Объект f2: x={0};

y={1}", f2.x, f2.y);

// Внесение изменений

f1.x = 1; f1.y = 2; f2.x = 3; f2.y = 4;

// Вывод после изменения

Console.WriteLine("\nСодержимое объектов

f1 и f2 после изменения");

Console.WriteLine("Объект f1: x={0};

y={1}", f1.x, f1.y);

Console.WriteLine("Объект f2: x={0};

y={1}", f2.x, f2.y);

while(true);

}

}

}

Листинг 12 . Код для переменных ссылочного типа

Результаты экрана

Содержимое объектов f1 и f2 до изменения

Объект f1: x=100; y=100

Объект f2: x=100; y=100

Содержимое объектов f1 и f2 после изменения

Объект f1: x=1; y=2

Объект f2: x=3; y=4

Соседние файлы в папке ИДПО_ИИИС