Читаем Интернет-журнал "Домашняя лаборатория", 2007 №9 полностью

Несмотря на то, что обстоятельный разговор о наследовании, родителях и потомках нам еще предстоит, лучше с самого начала понимать отношения между родительским классом и классом-потом ком, отношения между объектами этих классов. Класс-потомок при создании наследует все свойства и методы родителя. Родительский класс не имеет возможности наследовать свойства и методы, создаваемые его потомками. Наследование — это односторонняя операция от родителя к потомку. Ситуация с присваиванием симметричная. Объекту родительского класса присваивается объект класса-потомка. Объекту класса-потомка не может быть присвоен объект родительского класса. Присваивание — это односторонняя операция от потомка к родителю. Одностороннее присваивание реально означает, что ссылочная переменная родительского класса может быть связана с любыми объектами, имеющими тип потомков родительского класса.

Например, пусть задан некоторый класс Parent, а класс Child — его потомок, объявленный следующим образом:

class Child: Parent {…}

Пусть теперь в некотором классе, являющемся клиентом классов Parent и Child, объявлены переменные этих классов и созданы связанные с ними объекты:

Parent p1 = new Parent(), р2 = new Parent();

Child ch1 = new Child(), ch2 = new Child();

Тогда допустимы присваивания:

p1 = р2; р2= p1; ch1=ch2; ch2 = ch1; p1 = ch1; p1 = ch2;

Но недопустимы присваивания:

ch1 = p1; ch2 = p1; ch2 = p2; ch1 = p2;

Заметьте, ситуация не столь удручающая — сын может вернуть себе переданный родителю объект, задав явное преобразование. Так что следующие присваивания допустимы:

p1 = ch1;… ch1 = (Child)p1;

Семантика присваивания справедлива и для другого важного случая — при рассмотрении соответствия между формальными и фактическими аргументами процедур и функций. Если формальный аргумент согласно объявлению имеет тип T, а выражение, задающее фактический аргумент, имеет тип T1 то имеет место согласование типов формального и фактического аргумента, если и только если класс Т1 является потомком класса T. Отсюда незамедлительно следует, что если формальный параметр процедуры принадлежит классу Object, то фактический аргумент может быть выражением любого типа.

Преобразование к типу object

Рассмотрим частный случай присваивания х = е; когда х имеет тип object, в этом случае гарантируется полная согласованность по присваиванию — выражение е может иметь любой тип. В результате присваивания значением переменной х становится ссылка на объект, заданный выражением е. Заметьте, текущим типом х становится тип объекта, заданного выражением е. Уже здесь проявляется одно из важных различий между классом и типом. Переменная, лучше сказать сущность х, согласно объявлению принадлежит классу Object, но ее тип — тип того объекта, с которым она связана в текущий момент, — может динамически изменяться.

Примеры преобразований

Перейдем к примерам. Класс Testing, содержащий примеры, представляет собой набор данных разного типа, над которыми выполняются операции, иллюстрирующие преобразования типов. Вот описание класса Testing;

using System;

namespace Types

{

    ///

    /// Класс Testing включает данные разных типов. Каждый его

    /// открытый метод описывает некоторый пример,

    /// демонстрирующий работу с типами.

    /// Открытые методы могут вызывать закрытые методы класса.

    /// 

    public class Testing

    {

         /// 

         /// набор скалярных данных разного типа.

         /// 

         byte b = 255;

         int x = 11;

         uint ux = 1111;

         float у = 5.5f;

         double dy = 5.55;

         string s = "Hello!";

         string s1 = "25";

         object obj = new Object ();

         // Далее идут методы класса, приводимые по ходу

        // описания примеров

    }

В набор данных класса входят скалярные данные арифметического типа, относящиеся к значимым типам, переменные строкового типа и типа object, принадлежащие ссылочным типам. Рассмотрим закрытый (private) метод этого класса — процедуру WhoIsWho с формальным аргументом класса Object. Процедура выводит на консоль переданное ей имя аргумента, его тип и значение. Вот ее текст:

/// 

/// Метод выводит на консоль информацию о типе и

/// значении фактического аргумента. Формальный

/// аргумент имеет тип object. Фактический аргумент

/// может иметь любой тип, поскольку всегда

/// допустимо неявное преобразование в тип object.

/// 

///  — Имя второго аргумента

///  — Допустим аргумент любого типа

void WhoIsWho(string name, object any)

{

      Console.WriteLine("type {0} is {1}, value is {2}",

           name, any.GetType(), any.ToString ());

}

Вот открытый (public) метод класса Testing, в котором многократно вызывается метод WhoIsWho с аргументами разного типа:

/// 

/// получаем информацию о типе и значении

/// переданного аргумента — переменной или выражения ///

public void WhoTest()

{

     WhoIsWho("x",x);

     WhoIsWho("ux",ux);

     WhoIsWho("y",y);

     WhoIsWho("dy",dy);

     WhoIsWho ("s",s);

     WhoIsWho("11 + 5.55 + 5.5f",11 + 5.55 + 5.5f);

     obj = 11 + 5.55 + 5.5 f;

     WhoIsWho("obj",obj);

}

Перейти на страницу:

Похожие книги