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

В чём разница между new и override?

1.8 Middle🔥 201 комментариев
#C# и ООП

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

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

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

Разница между new и override в Unity (C#)

Различие между ключевыми словами new и override — фундаментальная концепция ООП в C#, критически важная для корректного наследования и полиморфизма. В контексте Unity это особенно актуально при создании пользовательских компонентов, MonoBehaviour, работе с ScriptableObjects или построении сложных иерархий классов.

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

Ключевые аспекты различия

1. override — Полиморфная перезапись

  • Изменяет реализацию виртуального (virtual) или абстрактного (abstract) метода базового класса.
  • Позволяет системе времени выполнения (runtime) определять, какую версию метода вызвать, основываясь на реальном (actual) типе объекта, а не на типе ссылки.
  • Гарантирует полиморфное поведение. Это основной инструмент для реализации разных поведений у объектов одного базового типа.

2. new — Сокрытие метода (Method Hiding)

  • Применяется к НЕ виртуальному методу базового класса.
  • Создаёт новый, независимый метод в производном классе, который скрывает унаследованную версию.
  • Какую версию метода вызвать, определяется компилятором на этапе компиляции, основываясь на типе ссылки (reference type), а не на реальном типе объекта.

Практический пример в контексте Unity

Представим базовый класс Enemy и производный BossEnemy.

public class Enemy : MonoBehaviour
{
    // Виртуальный метод - можно переопределить
    public virtual void Attack()
    {
        Debug.Log("Enemy attacks for 10 damage.");
    }

    // Не виртуальный (обычный) метод
    public void Taunt()
    {
        Debug.Log("Enemy taunts weakly.");
    }
}

public class BossEnemy : Enemy
{
    // ПЕРЕОПРЕДЕЛЕНИЕ: меняем поведение для ВСЕХ BossEnemy
    public override void Attack()
    {
        base.Attack(); // Можно вызвать базовую реализацию
        Debug.Log("Boss adds a shockwave for 20 extra damage!");
    }

    // СОКРЫТИЕ: создаём новый метод, скрывающий старый
    public new void Taunt()
    {
        Debug.Log("BOSS ROARS DEFIANTLY!");
    }
}

Тестируем разницу в поведении:

void TestEnemies()
{
    // Создаём объект BossEnemy
    BossEnemy boss = new BossEnemy();

    // Ссылка на BossEnemy как на базовый тип (Enemy)
    Enemy enemyReference = boss;

    Debug.Log("=== Вызов Attack() (override) ===");
    boss.Attack();        // Output: "Enemy attacks..." + "Boss adds shockwave..."
    enemyReference.Attack(); // Output: ТОТ ЖЕ РЕЗУЛЬТАТ! Реальный тип (Boss) определяет метод.

    Debug.Log("\n=== Вызов Taunt() (new) ===");
    boss.Taunt();            // Output: "BOSS ROARS DEFIANTLY!" (вызван метод из BossEnemy)
    enemyReference.Taunt();  // Output: "Enemy taunts weakly." (вызван метод из Enemy, т.к. тип ссылки - Enemy)
}

Сводная таблица различий

Аспектoverridenew
ЦельИзменить реализацию виртуального/абстрактного члена.Создать новый член, скрывающий унаследованный невиртуальный.
Базовый членДолжен быть virtual, abstract или уже override.Обычный (не виртуальный) член.
Разрешение вызоваДинамическое (во время выполнения). Зависит от реального типа объекта.Статическое (во время компиляции). Зависит от типа ссылки.
ПолиморфизмПоддерживает. Ядро полиморфного поведения.НЕ поддерживает. Ломает полиморфизм для этого метода.
Вызов базовой реализацииВозможен через base.MethodName().Возможен через приведение типа: ((BaseClass)this).MethodName().
Предупреждение компилятораОтсутствует, если используется корректно.CS0108: "BossEnemy.Taunt() скрывает унаследованный член Enemy.Taunt()...". Требует явного указания new.

Рекомендации для использования в Unity

  • Всегда предпочитайте override для изменения поведения. Это безопаснее и соответствует принципам ООП. В Unity это стандартный подход для кастомизации методов в пользовательских компонентах (например, Start(), Update() неявно виртуальны).
  • Ключевое слово new используйте с крайней осторожностью, обычно только при работе с чужими библиотеками или классами, где вы не можете изменить базовый метод на virtual, но вам необходимо использовать то же самое имя метода в производном классе для новой, не связанной функциональности. Это источник путаницы и ошибок.
  • При использовании new обязательно документируйте причину, чтобы избежать неожиданного поведения в будущем.

Таким образом, override — это инструмент для расширения и изменения логики в рамках полиморфной иерархии, в то время как new — это инструмент для сокрытия, который следует применять осознанно, понимая, что он обходит механизм полиморфизма. В разработке на Unity с её сильной ориентацией на компонентно-объектную модель, корректное использование override является залогом создания гибкой и расширяемой архитектуры игровых систем.