2016-02-25 20 views
5

Tôi có đơn giản ba lớp:Từ khóa mới: tại sao phương thức dẫn xuất không được gọi?

class A 
{ 
    public virtual void Write() 
    { 
     Console.Write("A"); 
    } 
} 

class B:A 
{ 
    public override void Write() 
    { 
     Console.Write("B"); 
    } 
} 

class C : B 
{ 
    public new void Write() 
    { 
     Console.Write("C"); 
    } 
} 

Và tôi đang tạo ra các đối tượng và gọi phương pháp của họ:

A a = new A(); 
a.Write(); 

A b = new C(); 
b.Write(); 

C c = new C(); 
c.Write(); 

Và đầu ra sẽ là: ABC

Những gì tôi không thể hiểu là tại sao những mã sản xuất B?:

A b = new C(); 
b.Write(); 

Tôi nghĩ rằng nó phải là C. Tuy nhiên, tôi đã kiểm tra nhiều lần và luôn là B.

Tôi hiểu rằng A b = new C() tạo loại đối tượng mới của C. Vậy đầu ra phải là C. Hoặc là hành vi đặc biệt để gọi phương thức ghi đè khi chúng ta sử dụng nó mà không cần truyền?

Tại sao điều đó xảy ra? Vì chúng tôi đã không sử dụng bất kỳ tham chiếu đến lớp B.

+5

Vì đó là cách từ khóa mới hoạt động. https://msdn.microsoft.com/en-us/library/ms173153.aspx – AndyJ

Trả lời

6

Nó sẽ có tác dụng nếu bạn muốn sử dụng ((C)b).Write();

Với new từ khóa bạn không trọng dụng phương pháp Write cho C nhưng thay vì tạo ra một phương pháp mới chỉ được định nghĩa cho C. Vì vậy, cho C của bạn, bạn thực sự có 2 phương thức có tên phương thức Write.

A c = new C(); 

c.Write();   //Output "B", you're calling the overridden method  
((C)c).Write();  //Output "C", you're calling the method defined on C 

//or 

(c as C).Write(); 

Cùng xảy ra khi bạn sẽ xác định c như C:

C c = new C(); 

c.Write();   //Output "C"  
((A)c).Write();  //Output "B" 

Trong ví dụ đầu tiên bạn gọi phương thức mới xác định trên C. Trong dòng thứ hai bạn đang gọi phương thức Write từ A, bị ghi đè bởi B, do đó đầu ra "B".

Edit: (một số giải thích thêm)

Biến c là loại A, vì vậy đó là những gì trình biên dịch của bạn biết "c là một thể hiện của A", nó không biết rằng nó thực sự là của một loại có nguồn gốc nhiều hơn. Khi bạn gọi phương thức Write trên nó, nó sẽ gọi phương thức được định nghĩa trên A (được overriden bởi B). Lớp cơ sở A của bạn không có kiến ​​thức về phương thức mới của bạn được xác định trên C (đó là những gì new thực hiện, tạo phương thức mới), vì vậy, trừ khi bạn truyền nó đến C để cho trình biên dịch biết về loại có nguồn gốc thực tế là c, lớp cơ sở của bạn sẽ được gọi.

+1

Thường được gọi là "ẩn thành viên" hoặc "ẩn bóng", hãy sử dụng nó một cách tiết kiệm và cẩn thận - có thể khá chói tai khi bạn mong đợi mã để làm điều gì đó khác. –

+0

Tôi xin lỗi vì câu hỏi câm của tôi, nhưng tại sao những mã này 'A b = new C(); b.Write(); 'gọi overriden phương pháp? Tôi có nghĩa là 'A b = new C()' tạo kiểu đối tượng mới 'C'. Vì vậy, đầu ra phải là 'C'. Hoặc đó là hành vi đặc biệt để gọi phương thức ghi đè khi chúng ta sử dụng nó mà không cần truyền? – StepUp

+0

Để truy cập một phương thức ẩn một phương thức khác, bạn cần một tham chiếu mạnh mẽ được nhập vào kiểu xác định ẩn, không phải là tham chiếu cơ sở. Quy tắc tương tự cũng áp dụng cho các giao diện được triển khai một cách rõ ràng.Về cơ bản nó không phải là thừa kế "đúng", vì vậy hệ thống phân cấp thừa kế không được thực thi theo cùng cách thức như một cuộc gọi phương thức được ghi đè chuẩn. –

Các vấn đề liên quan