Наследование (Is-a)

Когда мы работаем с классам и объектами мы можем связывать их не только с помощью ссылок между объектами (Has-a) но наследуя классы друг от друга (Is-a). Это удобно когда мы имеем несколько классов у которых есть нечто общее. При этом собрать все классы в один мы не можем.

Наследование нам также нужно для реализации полиморфизма подтипов. Обычно чисто наследование, без техник полиморфизма мы не используем. Но я постараюсь привести пару примеров.

Фрагмент 1.44

class Knight
{
    public int Health;
    public int Armor;

    public void TakeDamage(int damage)
    {
        Health -= damage - Armor;
    }

    public void Pray()
    {
        Armor += 1;
    }
}

class Barbarian
{
    public int Health;
    public int Armor;

    public void TakeDamage(int damage)
    {
        Health -= damage - Armor;
    }

    public void Waaaagh()
    {
        Health += 10;
        Armor -= 1;
    }
}

Как вы видите между этими классами много общего. Мы могли бы избавиться от дублирующегося кода с помощью связи Has-a, сделав третий класс Health и сделав ссылку у варвара и рыцаря на какое-то здоровье. И это могло бы сработать и чаще всего так и делается. Но не всегда. Иногда лучше сделать связь is-a, сказав что и варвар и рыцарь является чем-то, что содержит здоровье.

Фрагмент 1.45

class Warrior
{
    public int Health;
    public int Armor;

    public void TakeDamage(int damage)
    {
        Health -= damage - Armor;
    }
}
  
class Knight : Warrior
{
    public void Pray()
    {
        Armor += 1;
    }
}

class Barbarian : Warrior
{
    public void Waaaagh()
    {
        Health += 10;
        Armor -= 1;
    }
}

В данном случае мы сделали новый класс “воин”. И сказали что и рыцарь и варвар является воином а значит они содержат всё тоже, что содержит класс воин. Мы как бы перенесли всё, что внутри класса воин в классы рыцарь и варвар. При этом и рыцарь и варвар обладают уникальным возможностями. Рыцарь может помолится а варвар сделать Вааагх.

Цепочки вызовов конструкторов

Когда базовый класс (тот от когда наследуемся) имеет конструктор, то мы должны его вызвать в производном классе (тот который наследуется).

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

Фрагмент 1.46

class Warrior
{
    public int Health;
    public int Armor;

    public Warrior(int health, int armor)
    {
        Health = health;
        Armor = armor;
    }

    public void TakeDamage(int damage)
    {
        Health -= damage - Armor;
    }
}
  
class Knight : Warrior
{
    public Knight(int health, int armor) : base(health, armor) { }

    public void Pray()
    {
        Armor += 1;
    }
}

class Barbarian : Warrior
{
    public int LenghtOfAxe;

    public Barbarian(int health, int armor, int lenghtOfAxe) : base(health, armor)
    {
        LenghtOfAxe = lenghtOfAxe;
    }

    public void Waaaagh()
    {
        Health += 10;
        Armor -= 1;
    }
}

В базовом классе (воин) мы добавили конструктор для инициализации здоровья и брони. Это привело к тому, что нам пришлось определять конструкторы в производных классах со сходными параметрами для вызова конструктора базового класса.

Это происходит благодаря двоеточию после имени конструктора и ключевому слова base. Это и есть вызов конструктора базового класса. Мы можем передать ему те же значения что передали нам, а может подставить какие-нибудь литералы.

Фрагмент 1.47

public Barbarian(int armor, int lenghtOfAxe) : base(100, armor)
{
    LenghtOfAxe = lenghtOfAxe;
}

Например в этом случае все варвары создавались бы с фиксированным здоровьем и мы могли бы назначить им только броню.

Модификатор доступа protected

Базовый класс – это отдельный класс. Как бы это не звучало очевидно. Но вам стоит держать мысль о том, что раз класс отдельный то и проектируется он отдельно. Т.е нужно жестко сливать два класса. Базовый класс может содержать члены которые доступы производным классам. А может и сокрывать члены от всех, в том числе и от базовых классов.

При использование модификатора private член не доступен производному классу. А при использование protected член доступен только самому классу (как в случае с private) и в производном классе.

Если вы нашли ошибку, пожалуйста выделите её и нажмите Ctrl+Enter.


Leave a Reply

Your email address will not be published. Required fields are marked *