Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 9:

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

Если в крайнем слое адресуемого объекта вызываемая функция непереопределена или отсутствует в нем, ищется ее переопределение в ближайшем слое в сторону слоя базового класса.

Пример

using System;
    
namespace Test
{
    class Point
    {
        string name = "Слой Point";
        public virtual void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class Circle : Point
    {
        string name = "Слой Circle";
    
        public override void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class Cylinder : Circle
    {
        string name = "Слой Cylinder";
        new public void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    // Вызывающая сторона
    class MyClass
    {
        public MyClass()
        {
            // Создаем объекты для всех типов 
            // иерархической цепочки наследования
            // и адресуем их базовой ссылкой
            Point[] point = {
                new Point(),
                new Circle(),
                new Cylinder()
            };
    
            // Распечатываем
            Console.WriteLine("Адресация к ближайшей 
    виртуальной функции");
            for (int i = 0; i < point.Length; i++)
                point[i].Show();
    
            Console.WriteLine();
            Console.WriteLine("Адресуемся к слою 
    Cylinder напрямую");
            ((Cylinder)point[2]).Show();// Адресуемся напрямую
    
            // Извращенный синтаксис использования массива
            Console.WriteLine();
            Console.WriteLine("Нерациональный 
    синтаксис использования массива");
            for (int i = 0; i < 3; i++)
            {
                Point point1 = new Point[]{
                    new Point(),
                    new Circle(),
                    new Cylinder()
                }[i];
                point1.Show();
            }
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Механизм виртуальных функций";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 60;
            Console.WindowHeight = 15;
    
            new MyClass();// Чтобы сработал конструктор
    
            Console.ReadLine();
        }
    }
}
Листинг 9.15 . Поиск виртуальной функции по цепочке наследования

Результат выполнения будет такой


Мы видим, что при попытке адресации виртуальной функции в объекте Cylinder, которой в расширяющем слое этого объекта нет, вызвался вариант из слоя Circle. Тонкая ссылка при адресации к толстому объекту игнорирует невиртуальные функции в толстых слоях, поскольку они не включены в таблицу виртуальных функций. Если бы и в слое Circle объекта Cylinder этой функции не было, то вызвался бы вариант слоя Point. Если бы вообще этой функции не было ни в одном слое, то была бы сгенерирована ошибка компиляции как попытка вызова несуществующего члена.

Вот еще один отвлеченный пример адресации к ближайшей виртуальной функции

using System;
    
namespace Test
{
    class A
    {
        string name = "Слой A";
        public virtual void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class B : A
    {
        string name = "Слой B";
    }
    
    class C : B
    {
        string name = "Слой C";
        public override void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class D : C
    {
        string name = "Слой D";
    }
    
    class E : D
    {
        string name = "Слой E";
        public override void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class F : E
    {
        string name = "Слой F";
        public override void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    // Вызывающая сторона
    class MyClass
    {
        public MyClass()
        {
            // Создаем объекты для всех типов 
            // иерархической цепочки наследования
            // и адресуем их базовой ссылкой
            A[] a = {
                new A(),
                new B(),
                new C(),
                new D(),
                new E(),
                new F()
            };
    
            // Распечатываем
            Console.WriteLine("Адресация к ближайшей 
    виртуальной функции");
            Console.WriteLine("В классах B и D виртуальная функция отсутствует");
            for (int i = 0; i < a.Length; i++)
            {
                Console.Write("Объект " + 
      a[i].GetType().Name + "\t");
                a[i].Show();
            }
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Поиск виртуальной функции в 
    глубину наследования";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 60;
            Console.WindowHeight = 10;
    
            new MyClass();// Чтобы сработал конструктор
    
            Console.ReadLine();
        }
    }
}
Листинг 9.16 . Адресация к ближайшей виртуальной функции

и результат выполнения программы


Мы видим, что при адресации к слою, где функция не переопределена (слой B и D ), поиск по порядку ведется в ближайших от адресуемого слоях в направлении базового слоя.

using System;
    
namespace Test
{
    class A
    {
        string name = "Слой A";
    
        public virtual string Name
        {
            get { return name; }
        }
    
        public virtual void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class B : A
    {
        string name = "Слой B";
    
        public override string Name
        {
            get { return name; }
        }
    
        public override void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    class C : B
    {
        string name = "Слой C";
    
        public override string Name
        {
            get { return name; }
        }
    
        public override void Show()
        {
            Console.WriteLine(name);
        }
    }
    
    // Вызывающая сторона
    class MyClass
    {
        public MyClass()
        {
            A[] a = {
                new A(),
                new B(),
                new C()
            };
    
            // Распечатываем
            Console.WriteLine("Виртуальные методы:");
            for (int i = 0; i < a.Length; i++)
            {
                Console.Write("Объект " + 
      a[i].GetType().Name + "\t");
                a[i].Show();
            }
    
            // Распечатываем
            Console.WriteLine("\nВиртуальные свойства:");
            for (int i = 0; i < a.Length; i++)
            {
            Console.WriteLine("Объект " + 
    a[i].GetType().Name + "\t" + 
    "{0}", a[i].Name);
            }
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Виртуальные методы и свойства";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 60;
            Console.WindowHeight = 10;
    
            new MyClass();// Чтобы сработал конструктор
    
            Console.ReadLine();
        }
    }
}
Листинг 9.17 . Все сказанное про виртуальные функции справедливо и для виртуальных свойств

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

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

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

 

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