Ответ
Да, поведение метода можно изменить в производном классе, но механизм и семантика зависят от используемого подхода: полиморфное переопределение или скрытие метода.
1. Полиморфное переопределение (override):
Используется, когда метод базового класса помечен как virtual или abstract. Это основа полиморфизма.
class Logger {
public virtual void Log(string message) {
Console.WriteLine($"[INFO] {message}"); // Базовая реализация
}
}
class FileLogger : Logger {
public override void Log(string message) {
// Полностью новая реализация для файлового вывода
File.AppendAllText("log.txt", $"{DateTime.Now}: {message}n");
}
}
// Использование полиморфизма
Logger logger = new FileLogger();
logger.Log("Test"); // Вызовется FileLogger.Log
2. Скрытие метода (new):
Применяется, если метод базового класса не virtual. Создаётся новый, независимый метод с тем же именем.
class Base {
public void Display() => Console.WriteLine("Base.Display");
}
class Derived : Base {
public new void Display() => Console.WriteLine("Derived.Display");
}
// Поведение зависит от типа ссылки
Base obj1 = new Derived();
obj1.Display(); // Вывод: "Base.Display" (вызван метод из Base)
Derived obj2 = new Derived();
obj2.Display(); // Вывод: "Derived.Display" (вызван метод из Derived)
Практические рекомендации:
- Используйте
overrideдля реализации полиморфного поведения, когда разные типы объектов должны по-разному реагировать на один и тот же вызов метода. - Ключевое слово
newследует применять осознанно, обычно при расширении сторонних классов, где вы не можете изменить базовый код. Это может привести к путанице, так как поведение зависит от типа переменной, а не от реального объекта.
Ответ 18+ 🔞
Ну ты представляешь, в ООП эта тема с переопределением методов — это как с родственниками: можно либо унаследовать фамилию и продолжить династию, либо взять новую и делать вид, что ты не при делах. Вот смотри, как это работает на самом деле.
Если в базовом классе метод объявлен как virtual или abstract, то ты в наследнике можешь его полностью переписать под себя, и это будет честный полиморфизм. Все вызовы через базовый тип будут идти к твоей новой реализации — магия, блядь, в хорошем смысле.
class Logger {
public virtual void Log(string message) {
Console.WriteLine($"[INFO] {message}"); // Базовая, скучная реализация
}
}
class FileLogger : Logger {
public override void Log(string message) {
// А вот тут уже твои правила: пишем в файл, а не в консоль
File.AppendAllText("log.txt", $"{DateTime.Now}: {message}n");
}
}
// И вот тут прикол: даже если переменная типа Logger, вызовется метод из FileLogger
Logger logger = new FileLogger();
logger.Log("Test"); // Сработает FileLogger.Log, потому что override
А теперь второй вариант, когда в базовом классе метод не виртуальный. Тут уже история, как в плохом анекдоте: ты можешь создать метод с таким же именем в наследнике, но это будет совершенно отдельный метод, который просто прячет родительский. Это как надеть парик и усы — вроде похож, но система тебя не узнает.
class Base {
public void Display() => Console.WriteLine("Base.Display");
}
class Derived : Base {
public new void Display() => Console.WriteLine("Derived.Display"); // Новый метод, старый спрятан
}
// И вот тут начинается цирк
Base obj1 = new Derived();
obj1.Display(); // Выведет "Base.Display", потому что смотрим через тип Base
Derived obj2 = new Derived();
obj2.Display(); // А тут уже "Derived.Display", потому что тип Derived
Короче, если хочешь нормального полиморфизма, когда объект сам решает, какой метод вызывать, — используй override. А new — это такой костыль на крайний случай, когда трогать базовый код нельзя, но очень хочется своё впихнуть. Только не удивляйся потом, когда поведение будет прыгать в зависимости от типа переменной — это ж твой выбор, ёпта.