Опубликован: 25.03.2010 | Уровень: для всех | Доступ: платный
Лекция 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. Ввожу код на сайте, пишет:

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

 

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

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