Bất kỳ phương thức nào cũng có thể được ghi đè (= virtual) hoặc không. Quyết định được thực hiện bởi người xác định phương pháp:
class Person
{
public String GetPersonType()
{
return "person";
}
public virtual String GetName()
{
return "generic name";
}
}
Bây giờ bạn có thể ghi đè những phương thức có thể ghi đè:
class Friend : Person
{
public Friend() : this("generic name") { }
public Friend(String name)
{
this._name = name;
}
public override String GetName()
{
return _name;
}
}
Nhưng bạn không thể ghi đè GetPersonTypephương thức vì nó không ảo.
Hãy tạo hai phiên bản của các lớp đó:
Person person = new Person();
Friend friend = new Friend("Onotole");
Khi phương thức không ảo GetPersonTypeđược gọi theo Fiendtrường hợp, nó thực sự Person.GetPersonTypeđược gọi là:
Console.WriteLine(friend.GetPersonType());
Khi phương thức ảo GetNameđược gọi theo Friendtrường hợp, nó Friend.GetNameđược gọi là:
Console.WriteLine(friend.GetName());
Khi phương thức ảo GetNameđược gọi theo Persontrường hợp, nó Person.GetNameđược gọi là:
Console.WriteLine(person.GetName());
Khi phương thức không phải ảo được gọi, thân phương thức không được tra cứu - trình biên dịch đã biết phương thức thực cần được gọi. Trong khi với trình biên dịch các phương thức ảo không thể chắc chắn cái nào sẽ gọi và nó được tra cứu trong thời gian chạy trong hệ thống phân cấp lớp từ dưới lên bắt đầu từ kiểu thể hiện mà phương thức được gọi: vì friend.GetNamenó trông bắt đầu từ Friendlớp và tìm thấy nó ngay lập tức, đối với person.GetNamelớp học, nó bắt đầu từ Personvà tìm thấy nó ở đó.
Đôi khi bạn tạo một lớp con, ghi đè một phương thức ảo và bạn không muốn có thêm bất kỳ ghi đè nào trong hệ thống phân cấp - bạn sử dụng sealed overridecho điều đó (nói rằng bạn là người cuối cùng ghi đè phương thức):
class Mike : Friend
{
public sealed override String GetName()
{
return "Mike";
}
}
Nhưng đôi khi bạn của bạn Mike quyết định thay đổi giới tính của mình và do đó tên của anh ấy thành Alice :) Bạn có thể thay đổi mã gốc hoặc thay vào đó là phân lớp Mike:
class Alice : Mike
{
public new String GetName()
{
return "Alice";
}
}
Ở đây bạn tạo một phương thức hoàn toàn khác với cùng tên (bây giờ bạn có hai). Phương thức nào và khi nào được gọi? Nó phụ thuộc vào cách bạn gọi nó:
Alice alice = new Alice();
Console.WriteLine(alice.GetName());
Console.WriteLine(((Mike)alice).GetName());
Khi bạn gọi nó từ Alicequan điểm của bạn, bạn gọi Alice.GetName, khi từ góc độ Mikebạn gọi Mike.GetName. Không có tra cứu thời gian chạy nào được thực hiện ở đây - vì cả hai phương pháp đều không ảo.
Bạn luôn có thể tạo newcác phương thức - cho dù các phương thức bạn đang ẩn có phải là ảo hay không.
Điều này cũng áp dụng cho các thuộc tính và sự kiện - chúng được biểu diễn dưới dạng các phương thức bên dưới.