2012-01-11 41 views
5

Ai đó có thể giải thích sự khác biệt giữa hai ví dụ này là gì?Đa hình/ghi đè

Class A

protected virtual string GetData()

Class B

private override string GetData()

Và sau đây:

Class A

protected string GetData()

Class B

private string GetData()

Giả sử rằng kế thừa 'Class B' từ 'Class A'.

tôi luôn luôn giả định rằng bạn cần phải sử dụng virtual trong lớp cha và override trong lớp con nếu bạn muốn trọng của một phương pháp, tuy nhiên tôi đã cố gắng loại bỏ các từ khóa và các chương trình biên dịch tốt. Sự khác biệt chính xác là gì, nếu có?

+0

Bạn có thấy dấu gạch dưới B.GetData() không? Bạn có thấy cảnh báo trong Danh sách Xem + Lỗi không? Rất khó bỏ lỡ, hãy sử dụng từ khóa * mới * khi bạn biết mình đang làm gì. –

+1

Trong ví dụ đầu tiên, phương thức B không thể là riêng tư. Nó sẽ không biên dịch. – TrueWill

Trả lời

4

Ví dụ thứ hai mà bạn đã hiển thị ẩn GetData của phụ huynh, nó không ghi đè lên nó.

Ví dụ:

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

    public void Test2() 
    { 
     Console.WriteLine("Base"); 
    } 
} 

private class Derived : Base 
{ 
    public override void Test() 
    { 
     Console.WriteLine("Derived"); 
    } 

    public void Test2() 
    { 
     Console.WriteLine("Derived"); 
    } 
} 

static void Main() 
{ 
    Base b = new Base(); 
    Derived d = new Derived(); 
    Base dInB = new Derived(); 

    b.Test(); 
    d.Test(); 
    dInB.Test(); 

    b.Test2(); 
    d.Test2(); 
    dInB.Test2(); 

    Console.ReadKey(true); 
} 

Nó ra:

Base // Base.Test() 
Derived // Derived.Test() 
Derived // Derived.Test() 
Base // Base.Test2() 
Derived // Derived.Test2() 
Base // You think you're calling Derived.Test2(), but you actually call Base.Test2() 

Trên thực tế mẫu này là không hợp lệ, vì nó nên sử dụng từ khóa new trong public new void Test2() trong lớp Derived.

Nó hoạt động giống như quá tải toán tử. Nó không thực sự ghi đè lên bất cứ điều gì. Khi bạn có chính xác loại Derived, nó gọi phương thức mới.

Bạn phải thực sự cẩn thận với việc ẩn thành viên, không có gì giống như ghi đè (lớp) hoặc triển khai (giao diện) chút nào.Chỉ khi bạn cóchính xác, nó sẽ gọi phương thứcnew, nếu không nó sẽ vẫn gọi phương thức kiểu cơ sở!

+0

Cảm ơn, điều đó đã giúp làm rõ nó! –

+0

Bạn được chào đón :) – Aidiakapi

3

Sự khác biệt là trong trường hợp đầu tiên bạn ghi đè và trong trường hợp thứ hai bạn đang ẩn hoàn toàn khác.

Trong trường hợp thứ nhất:

class B: A 
{ 
    void Foo() 
    { 
     B b = new B(); 
     A a = b; 

     a.GetData() //B's GetData() will be called 
     b.GetData() //B's GetData() will be called 
    } 
} 

Mặt khác trong trường hợp thứ hai:

class B: A 
{ 
    void Foo() 
    { 
     B b = new B(); 
     A a = b; 

     a.GetData() //A's GetData() will be called 
     b.GetData() //B's GetData() will be called 
    } 
} 

Trong trường hợp thứ hai bạn chỉ đơn giản là đang lẩn trốn của một thi hành GetData() nhưng bạn sẽ luôn có thể gọi A thực hiện thông qua một biến gõ A ngay cả khi biến đề cập đến một thể hiện của loại B. Lưu ý rằng điều này là hoàn toàn khác với cách cư xử trọng.

+0

Cảm ơn bạn đã giải thích! –

0
public class A 
{ 
    public virtual string GetData() { return "A";} 
} 

public class B : A 
{ 
    public override string GetData() { return "B"; } 
} 

Bạn mong đợi điều gì khi sử dụng các lớp như trong khóa mã sau?

 A a = new A(); 
     B b = new B(); 
     A c = new B(); 

     Console.WriteLine(a.GetData()); 
     Console.WriteLine(b.GetData()); 
     Console.WriteLine(c.GetData()); 

Điều này sẽ in "A" "B" "B". Biến c được lưu trữ dưới dạng kiểu A nhưng khi thực thi phương thức, mã được giải quyết cho việc thực thi "thực". (xem google cho bảng chức năng ảo và nguyên tắc phân giải)

Nếu bạn không sử dụng ảo và ghi đè như trong mã bên dưới, thao tác này sẽ in "A" "B" "A".

public class A 
{ 
    public string GetData() { return "A";} 
} 

public class B : A 
{ 
    public new string GetData() { return "B"; } 
}