Tóm tắt nhanh
| Đặc điểm | Method Overriding | Method Hiding (Shadowing) |
|---|---|---|
| Từ khóa | virtual + override | new |
| Polymorphism | Có (runtime polymorphism) | Không (compile-time binding) |
| Base reference → Derived object | Gọi derived method | Gọi base method |
| Derived reference → Derived object | Gọi derived method | Gọi derived method |
| Truy cập base implementation | base.Method() | Không trực tiếp (cần cast) |
| Mục đích | Mở rộng/thay đổi hành vi | Đặt tên trùng, thay đổi signature, break inheritance |
Method Overriding (Ghi đè)
public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Animal sound");
}
}
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Woof!");
// base.MakeSound(); // Có thể gọi base
}
}
// Polymorphism hoạt động
Animal animal = new Dog();
animal.MakeSound(); // "Woof!" - Gọi Dog.MakeSound()
Method Hiding (Che giấu)
public class Animal
{
public void MakeSound()
{
Console.WriteLine("Animal sound");
}
}
public class Dog : Animal
{
// new keyword - hiding base method
public new void MakeSound()
{
Console.WriteLine("Woof!");
}
}
// Polymorphism KHÔNG hoạt động
Animal animal = new Dog();
animal.MakeSound(); // "Animal sound" - Gọi Animal.MakeSound()!
Dog dog = new Dog();
dog.MakeSound(); // "Woof!" - Gọi Dog.MakeSound()
So sánh hành vi chi tiết
public class Base
{
public virtual void VirtualMethod() => Console.WriteLine("Base.Virtual");
public void NonVirtualMethod() => Console.WriteLine("Base.NonVirtual");
}
public class Derived : Base
{
public override void VirtualMethod() => Console.WriteLine("Derived.Virtual");
public new void NonVirtualMethod() => Console.WriteLine("Derived.NonVirtual");
}
class Program
{
static void Main()
{
Base b = new Base();
Derived d = new Derived();
Base bd = new Derived(); // Base reference, Derived object
Console.WriteLine("--- Base instance ---");
b.VirtualMethod(); // Base.Virtual
b.NonVirtualMethod(); // Base.NonVirtual
Console.WriteLine("--- Derived instance ---");
d.VirtualMethod(); // Derived.Virtual
d.NonVirtualMethod(); // Derived.NonVirtual
Console.WriteLine("--- Base ref to Derived obj ---");
bd.VirtualMethod(); // Derived.Virtual (OVERRIDE works!)
bd.NonVirtualMethod(); // Base.NonVirtual (HIDING - base method!)
// Ép kiểu để gọi hidden method
((Derived)bd).NonVirtualMethod(); // Derived.NonVirtual
}
}
Kết quả
--- Base instance --- Base.Virtual Base.NonVirtual --- Derived instance --- Derived.Virtual Derived.NonVirtual --- Base ref to Derived obj --- Derived.Virtual Base.NonVirtual Derived.NonVirtual
Khi nào dùng Overriding vs Hiding?
Dùng Overriding (virtual/override) khi:
- Muốn polymorphism - hành vi thay đổi theo runtime type.
- Mở rộng chức năng base class (template method pattern).
- Thiết kế cho extensibility (plugin, framework).
Dùng Hiding (new) khi:
- Base class không phải virtual (sealed, third-party, legacy).
- Thay đổi signature (tham số, return type).
- Tên method trùng nhưng ngữ nghĩa hoàn toàn khác.
- Versioning: base class thêm method mới trùng tên với derived class cũ.
Versioning Scenario (Tại sao cần new)
// Version 1.0 - Base library
public class Logger
{
public void Log(string message) { Console.WriteLine(message); }
}
// Version 1.0 - Your code
public class MyLogger : Logger
{
public void Log(string message, LogLevel level) { ... } // Overload
}
// Version 2.0 - Base library thêm method mới
public class Logger
{
public void Log(string message) { ... }
public void Log(string message, LogLevel level) { ... } // NEW!
}
// Your code compile với v2.0:
// Warning: 'MyLogger.Log(string, LogLevel)' hides inherited member 'Logger.Log(string, LogLevel)'.
// Use 'new' keyword if hiding was intended.
// Fix: Thêm new keyword
public new void Log(string message, LogLevel level) { ... }
Warning CS0108
Nếu không dùng new khi hiding → Compiler warning CS0108: "Member hides inherited member. Use 'new' keyword if hiding was intended."
Sealed Override
public class Base
{
public virtual void Method() { }
}
public class Middle : Base
{
public sealed override void Method() { } // Không cho derived override nữa
}
public class Derived : Middle
{
// public override void Method() { } // ❌ Error: cannot override sealed method
public new void Method() { } // Chỉ có thể hiding
}
Best Practices
- Mặc định: virtual/override cho polymorphism.
- Chỉ dùng
new khi bắt buộc (base không virtual, versioning conflict). - Luôn thêm
newexplicit khi hiding để tắt warning và thể hiện ý định. - XML doc:
<inheritdoc/>cho override, doc riêng cho hiding. - Code review: Kiểm tra hiding có ý định không.