Опубликован: 25.03.2010 | Уровень: для всех | Доступ: платный
Лекция 9:

Наследование в C#

Сокрытие имен при наследовании

Находясь внутри производного класса мы можем видеть как-бы два слоя членов: члены производного класса на переднем плане и члены базового класса на заднем плане. Производный и базовый классы могут иметь члены с одинаковыми именам и. Это не является ошибкой, и даже компилятор не выдаст предупреждение, что будет использован член производного класса. Лишь текстовый редактор оболочки напомнит подчеркиванием, что имя члена в производном классе, находящееся в переднем слое, скрывает имя члена базового класса и желательно использовать ключевое слово new, но можно обойтись и без него. Употребление ключевого слова new в данном контексте свидетельствует лишь о том, что программист извещен и знает, что делает. Вот пример

using System;
    
namespace Test
{
    class A
    {
        protected int x; // Член класса A будет виден в наследниках
    
        public A(int a)
        {
            x = a;
        }
    
        public A()// Обязаны определить
        { }
    
        protected int Get() // Член класса A будет виден в наследниках
        {
            return x;
        }
    }
    
    class Empty : A
    {
        public Empty(int a)
            : base(a)
        { }
    
        public Empty() { }  // Обязаны определить, 
                            // если определен в базовом классе
    }
    
    class B : Empty
    {
        new int x; // Член класса B, одноименный с унаследованным
    
        public B(int a, int b)
            : base(a)
        {
            x = b;  // Значение присваивается члену текущего класса
        }
    
        public B(int x)
        {
            base.x = 10;// Значение присваивается члену базового класса
            this.x = x; // Значение присваивается члену текущего класса
        }
    
        new int Get() // Член класса B, одноименный с унаследованным
        {
            return x;
        }
    
        public void Show()
        {
            int sumOfSquares =
                base.Get() * base.Get() // Используется унаследованный член 
                + Get() * Get();    // Используется член текущего класса
            Console.WriteLine("Сумма квадратов: 
    {0}", sumOfSquares);
        }
    }
    
    // Вызывающий код
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Сокрытие унаследованных имен";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 60;
            Console.WindowHeight = 10;
    
            B ob = new B(1, 2);
            ob.Show();
            Console.WriteLine("Контрольная сумма 
    квадратов: {0}", 1 + 4);
            Console.WriteLine();
    
            ob = new B(5);// Использование ссылки для другого объекта
            ob.Show();
            Console.WriteLine("Контрольная сумма квадратов: 
    {0}", 125);
    
            Console.ReadLine();
        }
    }
}
Листинг 9.7 . Доступ к одноименным членам в цепочке наследования

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

Последовательность срабатывания конструкторов

В многоуровневой цепочке наследования производный класс стоит в самом низу иерархической лестницы. Если создается объект этого составного класса, то срабатывание конструкторов выполняется в сторону производного класса, начиная с конструктора базового класса, в порядке их выведения. Деструкторы срабатывают в обратном порядке и только при активизации сборщика мусора ( GC - Garbare Collector ). Вот пример

using System;
    
namespace Test
{
    class A
    {
        public A()
        {
            Console.WriteLine("Сработал конструктор A");
        }
    
        ~A()
        {
            Console.WriteLine("Сработал деструктор A");
        }
    }
    
    class B : A
    {
        public B()
        {
            Console.WriteLine("Сработал конструктор B");
        }
    
        ~B()
        {
            Console.WriteLine("Сработал деструктор B");
        }
    }
    
    class C : B
    {
        public C()
        {
            Console.WriteLine("Сработал конструктор C");
        }
    
        ~C()
        {
            Console.WriteLine("Сработал деструктор C");
        }
    }
    
    class D : C
    {
        public D()
        {
            Console.WriteLine("Сработал конструктор D");
        }
    
        ~D()
        {
            Console.WriteLine("Сработал деструктор D");
        }
    }
    
    // Вызывающий код
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Вызовы конструкторов и деструкторов";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 60;
            Console.WindowHeight = 10;
    
            D ob = new D(); // Создаем объект
            ob = null;  // Теряем объект, чтобы сработали деструкторы
            Console.WriteLine();// Новая строка в выводе
    
            GC.Collect();// Принудительно вызываем сборщик мусора
            GC.WaitForPendingFinalizers();  // Приостанавливаем текущий поток
                                            // до завершения уборки
    
            Console.ReadLine();
        }
    }
}
Листинг 9.8 . Порядок срабатывания конструкторов и деструкторов в иерархической лестнице

Результат вывода будет таким


Порядок корректного срабатывания конструкторов и деструкторов удобно представить как модель строительства и разрушения многоэтажного дома


Конструкторы устанавливают составной объект в нужное состояние, назначая полям заданные значения. Естественно, что вначале должна быть создана базовая часть объекта, как фундамент всей последующей надстройки частей, описанных в производных классах. Деструкторы срабатывают в порядке, обратном порядку создания конструкторов, обеспечивая последовательное разрушение объекта по направлению к фундаменту.

Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?

Денис Пашков
Денис Пашков
Россия
Татьяна Ковалюк
Татьяна Ковалюк
Украина, Киев, Киевский политехнический институт, 1974