Bất kỳ phương pháp nào cũng có thể được ghi đè (= virtual
) hay không. Quyết định được thực hiện bởi một trong những người định nghĩa phương pháp:
class Person
{
// this one is not overridable (not virtual)
public String GetPersonType()
{
return "person";
}
// this one is overridable (virtual)
public virtual String GetName()
{
return "generic name";
}
}
Bây giờ bạn có thể ghi đè lên các phương pháp đó có overridable:
class Friend : Person
{
public Friend() : this("generic name") { }
public Friend(String name)
{
this._name = name;
}
// override Person.GetName:
public override String GetName()
{
return _name;
}
}
Nhưng bạn không thể ghi đè lên các phương pháp GetPersonType
vì nó không phải là ảo.
Hãy tạo ra hai trường hợp của những lớp:
Person person = new Person();
Friend friend = new Friend("Onotole");
Khi phương pháp không ảo GetPersonType
được gọi bởi Fiend
dụ nó thực sự Person.GetPersonType
đó được gọi là:
Console.WriteLine(friend.GetPersonType()); // "person"
Khi phương pháp ảo GetName
được gọi là bởi Friend
thể hiện là Friend.GetName
được gọi là:
Console.WriteLine(friend.GetName()); // "Onotole"
Khi phương pháp ảo GetName
được gọi bởi Person
dụ nó Person.GetName
đó được gọi là:
Console.WriteLine(person.GetName()); // "generic name"
Khi phương pháp không ảo được gọi là thân phương pháp không được ngẩng đầu lên - trình biên dịch đã biết phương pháp thực tế mà cần được gọi là. Trong khi các trình biên dịch phương thức ảo không thể chắc chắn cái nào cần 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 cá thể mà phương thức được gọi là: friend.GetName
, nó bắt đầu tại Friend
lớp học và tìm thấy nó ngay lập tức, cho person.GetName
lớp nó bắt đầu tại Person
và tìm thấy nó ở đó.
Đôi khi bạn thực hiện một lớp con, ghi đè lên một phương pháp ảo và bạn không muốn bất kỳ ghi đè hơn xuống trong hệ thống phân cấp - bạn sử dụng sealed override
cho rằng (nói rằng bạn là người cuối cùng ai sẽ ghi đè phương pháp):
class Mike : Friend
{
public sealed override String GetName()
{
return "Mike";
}
}
Nhưng đôi khi bạn bè của bạn Mike quyết định thay đổi giới tính của mình và do đó tên của mình để Alice :) bạn có thể có thể thay đổi mã gốc hoặc thay vì phân lớp Mike:
class Alice : Mike
{
public new String GetName()
{
return "Alice";
}
}
Ở đây bạn tạo ra một phương pháp hoàn toàn khác nhau có cùng tên (bây giờ bạn có hai). Phương pháp nào và khi nào được gọi? Nó phụ thuộc vào cách bạn gọi nó là:
Alice alice = new Alice();
Console.WriteLine(alice.GetName()); // the new method is called, printing "Alice"
Console.WriteLine(((Mike)alice).GetName()); // the method hidden by new is called, printing "Mike"
Khi bạn gọi nó từ Alice
'quan điểm của bạn gọi Alice.GetName
, khi từ Mike
' s - 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 thức đều không phải là ảo.
Bạn luôn có thể tạo các phương thức new
- cho dù các phương pháp 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 thể hiện dưới dạng phương thức bên dưới.
cảm ơn cho đầu vào .. nhưng một điều không nhận được trong tâm trí của tôi là ..điều gì đang sử dụng Base b = new Derived()? Đây có phải là đối tượng tạo lớp cơ sở hoặc lớp dẫn xuất không ?? –
Lớp có nguồn gốc. Tôi nghĩ bạn phải tìm hiểu thêm về tính đa hình. Đây là một cách tốt để bạn đọc. http://msdn.microsoft.com/en-us/library/ms173152 (v = vs.80) .aspx – CharithJ
@Xor: Trong trường hợp đó, bạn đang tạo một cá thể của đối tượng 'Derived' và lưu trữ tham chiếu trong biến' Base'. Điều này là hợp lệ vì một đối tượng 'Derived' là một đối tượng' Base'. Điều đó giống như nói rằng chúng ta cần một "người" để chúng ta có được "Johnny", người sẽ là một người. Cùng một thỏa thuận ở đây. –