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 đè GetPersonType
phươ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 Fiend
trườ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 Friend
trườ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 Person
trườ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.GetName
nó trông bắt đầu từ Friend
lớp và tìm thấy nó ngay lập tức, đối với person.GetName
lớp học, nó bắt đầu từ Person
và 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 override
cho đ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ừ Alice
quan điểm của bạn, bạn gọi Alice.GetName
, khi từ góc độ Mike
bạ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 new
cá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.