2010-06-01 37 views
25

Tôi đang gặp các loại sau đây:Nhầm lẫn về "ghi đè" và "mới" trong C#

class Base 
{ 
    public virtual void Print() 
    { 
     Console.WriteLine("Base"); 
    } 
} 

class Der1 : Base 
{ 
    public new virtual void Print() 
    { 
     Console.WriteLine("Der1"); 
    } 
} 

class Der2 : Der1 
{ 
    public override void Print() 
    { 
     Console.WriteLine("Der2"); 
    } 
} 

Đây là phương pháp chính của tôi:

Base b = new Der2(); 
Der1 d1 = new Der2(); 
Der2 d2 = new Der2(); 

b.Print(); 
d1.Print(); 
d2.Print(); 

Đầu ra là Base, Der2, Der2.

Theo như tôi biết, Ghi đè sẽ không cho phép phương thức trước đó chạy, ngay cả khi con trỏ trỏ đến chúng. Vì vậy, dòng đầu tiên cũng nên xuất ra Der2. Tuy nhiên Base xuất hiện.

Làm cách nào có thể? Cách ghi đè không hoạt động ở đó?

+0

Thật Một ví dụ tuyệt vời ... Bí quyết duy nhất ở đây là: - intially, phương pháp BASE đã được ẩn bằng phương pháp ảo của "Der-1", do đó quá đi xe phương pháp "Der-2 "KHÔNG THỂ được thực hiện. Vì vậy, chúng tôi đã nhận được giá trị của BASE. – Kings

Trả lời

27

Bạn chưa bao giờ thực sự ghi đè phiên bản Base của Print(). Bạn chỉ ẩn nó với một phương pháp ảo riêng biệt (có tên giống nhau) trong Der1.

Khi bạn sử dụng từ khóa new trên chữ ký phương thức - bạn đang nói trình biên dịch rằng đây là phương pháp có cùng tên như một phương thức của một trong các lớp cơ sở của bạn - nhưng không có mối quan hệ nào khác. Bạn có thể làm cho phương thức mới này ảo (như bạn đã làm) nhưng nó không giống như phương thức overriding của lớp cơ sở.

Trong Der2 khi bạn ghi đè Print, bạn thực sự ghi đè phiên bản 'mới' mà bạn đã khai báo trong Der1 - không phải phiên bản là Base. Eric Lippert có một số excellent answer cho một câu hỏi hơi khác có thể giúp bạn giải thích lý do phương pháp ảo được xử lý bằng ngôn ngữ C#.

Trong ví dụ của bạn, khi bạn gọi Print, bạn đang gọi nó trong trường hợp đầu tiên thông qua một tài liệu tham khảo của loại Base - vì vậy các ẩn (nhưng không overriden) phiên bản của Print được gọi. Hai cuộc gọi khác được gửi đến thực hiện của Der1, bởi vì trong trường hợp này, bạn đã thực sự overriden phương pháp.

Bạn có thể đọc thêm về điều này trong số MSDN documentation of new and override.

gì bạn có thể đã có ý định làm gì với Der1 (như bạn đã làm với Der2) là sử dụng override keyword:

class Base 
{ 
    public virtual void Print() 
    { 
     Console.WriteLine("Base"); 
    } 
} 

class Der1 : Base 
{ 
    // omitting 'new' and using override here will override Base 
    public override void Print() 
    { 
     Console.WriteLine("Der1"); 
    } 
} 
+0

Đó là những gì anh ta đã làm với Der2. – GalacticCowboy

+0

@GalacticCowboy - thực sự, đó là quan điểm của tôi. Đó có lẽ là những gì đã được dự định trong Der1 là tốt, nhưng bằng cách nào đó từ khóa 'mới' đã bị trượt vào, thay vì' override'. Tôi sẽ cập nhật bài đăng của mình để làm rõ hơn. – LBushkin

+0

Cảm ơn bạn. Một câu trả lời tuyệt vời, tôi hoàn toàn hiểu nó hoạt động như thế nào bây giờ. – iTayb

5

Đó là vì Der1 không overridePrint, nó thay thế nó bằng một phương pháp mới hoàn toàn có cùng tên (điều này là do việc sử dụng từ khóa new). Vì vậy, khi đối tượng được truyền tới Base, nó gọi số Print trong Base; không có ghi đè để gọi ..

1

override sẽ thay thế các phương pháp trước đó, nhưng khi lớp Der1 của bạn không ghi đè Print() (nó bóng nó, để sử dụng một VB-ism), sau đó các verion overriden hầu hết Base 's Print() được gọi, mà xảy ra với là phiên bản nó định nghĩa

0

Vì mọi người đã nói rằng lớp Der1 đang thay thế Print() thay vì ghi đè lên. Để xem điều này hoạt động, bạn có thể căn cứ d1d2 đến Base và sau đó gọi phương thức in. Sau đó, nó sẽ trả về Base.

((Base)d2).Print(); //Base