← Назад к вопросам

Приведи пример Наследования

1.3 Junior🔥 172 комментариев
#C# и ООП

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример наследования в C# для Unity

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

Базовый пример: создание иерархии персонажей

Рассмотрим классический пример с игровыми персонажами. У нас будет базовый класс Character, от которого наследуются более специализированные классы Warrior и Mage.

1. Базовый (родительский) класс Character

Этот класс определяет общие для всех персонажей свойства и поведение.

using UnityEngine;

public class Character : MonoBehaviour
{
    // Общие защищенные поля, доступные в классах-
    protected string characterName;
    protected int health;
    protected float moveSpeed;

    // Конструктор для базовой инициализации
    public Character(string name, int initialHealth, float speed)
    {
        characterName = name;
        health = initialHealth;
        moveSpeed = speed;
        Debug.Log($"Создан персонаж: {characterName}");
    }

    // Общий метод для движения
    public virtual void Move(Vector3 direction)
    {
        transform.Translate(direction * moveSpeed * Time.deltaTime);
        Debug.Log($"{characterName} движется со скоростью {moveSpeed}");
    }

    // Общий метод для получения урона
    public virtual void TakeDamage(int damage)
    {
        health -= damage;
        Debug.Log($"{characterName} получает {damage} урона. Здоровье: {health}");
        if (health <= 0)
        {
            Die();
        }
    }

    // Общий метод, который могут переопределить потомки
    protected virtual void Die()
    {
        Debug.Log($"{characterName} погибает.");
        // Базовая логика уничтожения объекта
        Destroy(gameObject);
    }

    // Общее свойство для чтения здоровья
    public int Health => health;
}

2. Производный класс Warrior

Класс-воин наследует всё от Character и добавляет свою специфику.

public class Warrior : Character
{
    // Новое уникальное поле
    private int armor;

    // Конструктор вызывает конструктор базового класса через base()
    public Warrior(string name, int initialHealth, float speed, int armorValue) 
        : base(name, initialHealth, speed)
    {
        armor = armorValue;
        Debug.Log($"Это воин с бронёй {armor}");
    }

    // Переопределение метода получения урона с учётом брони
    public override void TakeDamage(int damage)
    {
        int reducedDamage = Mathf.Max(damage - armor,总量 1); // Минимум 1 урон
        base.TakeDamage(reducedDamage); // Вызов родительской логики
        Debug.Log($"Броня поглотила часть урона! Реальный урон: {reducedDamage}");
    }

    // Новый уникальный метод
    public void ShieldBash()
    {
        Debug.Log($"{characterName} совершает удар щитом!");
        // Логика атаки...
    }

    // Переопределение метода смерти для воина
    protected override void Die()
    {
        Debug.Log($"Воин {characterName} пал в бою с честью!");
        base.Die(); // При необходимости вызываем базовый метод
    }
}

3. Производный класс Mage

Класс.маг также наследует Character, но реализует магическую специфику.

public class Mage : Character
{
    // Новое уникальное поле
    private int mana;

    public Mage(string name, int initialHealth, float speed, int initialMana) 
        : base(name, initialHealth, speed)
    {
        mana = initialMana;
        Debug.Log($"Это маг с {mana} единицами маны.");
    }

    // Переопределение метода движения (маги движутся медленнее при низкой мане)
    public override void Move(Vector3 direction)
    {
        float currentSpeed = mana > 50 ? moveSpeed : moveSpeed * 0.5f;
        transform.Translate(direction * currentSpeed * Time.deltaTime);
        Debug.Log($"{characterName} движется со скоростью {currentSpeed} (мана: {mana})");
    }

    // Уникальный метод мага
    public void CastSpell(string spellName, int manaCost)
    {
        if (mana >= manaCost)
        {
            mana -= manaCost;
            Debug.Log($"{characterName} сотворяет заклинание '{spellName}'! Осталось маны: {mana}");
        }
        else
        {
            Debug.Log($"Недостаточно маны для заклинания '{spellName}'");
        }
    }

    // Свойство только для чтения для доступа к мане
    public int Mana => mana;
}

Как это работает в Unity

// Пример использования в другом скрипте (например, GameManager)
public class GameManager : MonoBehaviour
{
    void Start()
    {
        // Создание экземпляров. В реальном проекте они бы были компонентами на GameObject.
        Character genericCharacter = new Character("Базовый", 100, 5f);
        Warrior knight = new Warrior("Артур", 150, 4f, 10);
        Mage merlin = new Mage("Мерлин", 80, 3.5f, 200);

        // Работа с общим интерфейсом родительского класса
        Character[] party = new Character[] { knight, merlin };

        foreach (Character character in party)
        {
            character.Move(Vector3.forward); // Вызовется переопределённый метод для каждого типа
            character.TakeDamage(30); // Воин получит меньше урона из-за брони
        }

        // Использование специфичных методов
        knight.ShieldBash(); // Только у Warrior есть этот метод
        merlin.CastSpell("Огненный шар", 40); // Только у Mage есть этот метод

        // Проверка типа (кастинг)
        if (merlin is Mage)
        {
            Mage mageRef = merlin as Mage;
            Debug.Log($"Мана мага: {mageRef.Mana}");
        }
    }
}

Ключевые преимущества наследования в Unity:

  • Повторное использование кода (DRY): Общая логика (движение, здоровье) пишется один раз в базовом классе.
  • Полиморфизм: Мы можем работать с массивами типа Character, вызывая методы, которые будут выполнены в зависимости от реального типа объекта (Warrior или Mage).
  • Расширяемость: Легко добавлять новые типы персонажей (например, Archer), наследуя от Character и добавляя уникальные особенности.
  • Организация кода: Чёткая иерархия классов упрощает понимание архитектуры проекта.
  • Совместимость с Unity: Наследование от MonoBehaviour — основа для создания компонентов. Вы можете создавать свои базовые компоненты (например, DamageableEntity), от которых наследуют конкретные реализации.

Важное замечание: В Unity часто используют композицию (добавление отдельных компонентов) вместе с наследованием. Например, вместо глубокой иерархии классов для всех типов врагов, вы можете создать базовый класс EnemyAI и добавлять к нему компоненты ShootingComponent, MeleeComponent и т.д. Наследование идеально подходит для создания "is-a" отношений (Warrior is a Character), а композиция — для "has-a" отношений (Character has a Inventory).