Разработка приложений на языке C#. Полезные настройки. Особые спецификаторы формата, страница 12

    Console.Write("Age: ");      // Возраст – это целое

             age = int.Parse (Console.ReadLine()); // Преобразуем введенную строку в целое без знака

  }

  public void Out()            // Метод вывода данных

  {

    Console.WriteLine (this); // Выводим себя. Что это?

  }

Обратимся к файлу TestMan.cs. Введите изменения, которые декларируют испытуемый класс Man, а также содержат код для проверки его функционирования. Заметьте, что теперь в домике MyConsole спрятаны 2 домика: Man и Program.

  static void TestMan()  //==== Пытаемся использовать подход, принятый в С++

  {

    Console.Clear();

    Console.WriteLine("Test Man\n");

    Man m;   // Создаем объект класса Man

    m.Out(); // Посылаем ему сообщение о выводе данных

    Console.WriteLine("\n\t\tPress any key to go to main menu\n");

    Console.ReadKey(true);

  }

Ссылка — это завуалированный указатель

Если вы попытаетесь построить проект (F6) в таком виде, то получите сообщение об ошибке:

Use of unassigned local variable 'm'

Оказывается мы используем не инициализированную переменную m. Здесь проявляется одно из фундаментальных отличий подхода к обработке данных, исповедуемом CLR, от подхода, используемого в проектах C++ (Win32 API). Все типы данных в .NET делятся на две категории: Value types и Reference types.

·  Первая категория объединяет те простые типы, память для которых отводится в стеке на этапе компиляции (то есть рано). Отметьте, что struct тоже является простым типом данных (value type).

·  Вторая категория объединяет массивы переменных и классы, память для которых выделяется в области heap на этапе выполнения, то есть поздно.

Stack

 

Первые являются обычными переменными, а вторые — ссылками. Переменная m типа Man в языке C# является не объектом класса Man, как принято в непричесанном (unmanaged) С++. Это—всего лишь неинициализированная (null) ссылка на объект (сам объект должен жить в Heap). Ссылка m живет в Stack и занимает всего 4 байта.

Объявление Man m; в C# не означает создание объекта класса с помощью default-конструктора, а создание ссылки (адреса со значением null). Если мы действительно хотим создать объект класса Man, то надо сделать это динамически (с помощью операции new). Только в этот момент будет вызван тот или иной конструктор.

Man m = new Man();  // Динамическое создание объекта

Введите исправление и запустите проект. Теперь все пройдет гладко и в консольном окне вы увидите как работает метод WriteLine класса Console, определенного в пространстве имен System. Он выводит объект класса Man, идентифицируемый ссылкой this. В окне появится строка: MyConsole.Man. Так по умолчанию интерпретируется ссылка this при попытке вывода ее в консольное окно. Это все, что знает о нас родитель (класс object). При выводе активного объекта (ассоциируемого со ссылкой m) к нему применяется родительский метод ToString().

Класс Object — суперкласс для всех классов системы

Наш класс, как и все другие классы платформы .NET, имеет неявного родителя. Им является класс Object — суперкласс для всех классов платформы .NET. Настоящий момент является весьма удобным для того, чтобы вспомнить ООП и проверить наше умение переопределять виртуальные функции. Так как класс Man (на равне со всеми другими классами) происходит от класса Object, то функция ToString унаследована им от своего родителя. Она является виртуальной и, следовательно, в классе Man мы можем создать ее новую версию (overriden version). Введите в состав класса Man функцию ToString, которая предлагает более осмысленную идентификацию объекта, чем просто имя класса, данное нам по умолчанию.

public override string ToString() { return . . .; } // Вставьте свой код

В языке С# все виртуальные функция обязаны иметь описатель virtual в тех базовых классах, где они появляются впервые. Все производные классы должны сопровождать свои версии виртуальных функций описателем override, при виде которого вы моментально узнаете, что класс имеет наследство.