2012-05-05 22 views
6

Tôi là lập trình viên C# mới cho ngôn ngữ D. Tôi hơi bối rối với ngôn ngữ lập trình OOP trong D.Tại sao một chức năng với công cụ sửa đổi được bảo vệ có thể bị ghi đè và truy cập mọi nơi?

Giả sử rằng tôi có lớp sau đây:

public class A { 
    protected void foo() { 
     writefln("A.foo() called."); 
    } 
}; 

public class B : A { 
    public override void foo() { 
     writefln("B.foo() called."); 
    } 
}; 

Các modifier protected có nghĩa là tôi có thể truy cập các phương pháp .foo() chỉ trên lớp được thừa kế, vậy tại sao D chương trình này biên dịch bình thường?

Dưới đây là tương đương với C# .NET:

using System; 

public class A { 
    protected virtual void foo() { 
     Console.WriteLine("a.foo() called."); 
    } 
}; 

public class B : A { 
    public override void foo() { 
     Console.WriteLine("b.foo() called."); 
    } 
}; 

public class MainClass { 
    public static void Main(string[] args) { 
     A a = new A(); 
     B b = new B();  
     a.foo(); 
     b.foo(); 
    } 
}; 

Nó không biên dịch và đưa ra các thông báo lỗi sau (như tôi dự kiến):

Test.cs (10 , 30): lỗi CS0507: B.foo()': cannot change access modifiers when overriding bảo vệ 'thừa hưởng' thành viên A.foo()'

ai đó có thể giải thích hành vi D này? Cảm ơn trước.

+2

Tại sao bạn nhầm lẫn? C# và D chỉ là các ngôn ngữ khác nhau, vì vậy chúng làm việc khác nhau. Thoạt nhìn, cả hai cách tiếp cận đều có ý nghĩa với tôi, do đó, nó phụ thuộc vào các nhà thiết kế ngôn ngữ để quyết định nên đi theo con đường nào. – svick

+0

Humm, bởi vì tôi đã nhớ rằng các bộ điều khiển truy cập của một ngôn ngữ lập trình hướng đối tượng hoạt động theo cùng một cách. – Jack

+0

downvotes- có thể giải thích xin vui lòng? – Jack

Trả lời

16

Không có mục đích trong việc ngăn ghi đè. Lớp dẫn xuất có thể thực hiện một hàm chuyển tiếp tầm thường cho phép truy cập. Xem xét:

public class A { 
    protected void foo() { 
     writefln("A.foo() called."); 
    } 
}; 

public class B : A { 
    protected override void foo() { // OK 
     writefln("B.foo() called."); 
    } 
    public void call_foo() { 
     foo(); // But I allowed public access anyway! 
    } 
}; 

Như vậy, mặc dù tôi đã không xác định lại mức độ tiếp cận của foo, tôi vẫn cho phép truy cập công cộng để nó và không có gì bạn có thể làm gì về nó là. Việc cho phép định nghĩa lại chỉ đơn giản hơn.

+0

Humm, sau đó là thiết kế 'D'. Trong ngôn ngữ 'C# .NET', không thể viết một cái gì đó giống như phương thức' call_foo() '. Nó cho một 'lỗi CS0122: A.foo() 'là không thể truy cập do mức độ bảo vệ của nó.' Cảm ơn bạn đã trả lời. :) – Jack

+0

@Jack: Cái gì, trong C# bạn không thể viết một phương thức công khai gọi là phương thức được bảo vệ? – Puppy

+0

Không. Đừng làm việc cho tôi, tôi đã thử nghiệm trên C# -Mono và nó đưa ra thông báo lỗi trên. – Jack

5

Hành vi của D trong này khớp với hành vi của Java. Một lớp dẫn xuất có thể cung cấp cho hàm của nó một mức truy cập ít hạn chế hơn một hàm trên hàm trong lớp cơ sở nhưng không phải là một hàm hạn chế hơn. Vì vậy, một hàm protected có thể bị ghi đè là protected hoặc public, nhưng không thể ghi đè là private và chức năng public chỉ có thể được ghi đè là public.

Tôi không biết tại sao C# sẽ hạn chế protected sao cho bạn không thể ghi đè lên bằng chức năng public. Là một người lập trình rất nhiều trong C++, D, và Java nhưng rất ít trong C#, C# 's sự lựa chọn ở đây làm cho rất ít ý nghĩa với tôi. C++, D và Java đều cho phép.

7

Vì có một số câu trả lời tuyệt vời cho câu hỏi "tại sao nó có thể?" Tôi nghĩ C# xứng đáng giải thích tại sao nó KHÔNG thể: Đó là về "triết lý" của một thiết kế ngôn ngữ, và có thể được đun sôi xuống để "là một" vs "có-một" xung đột các ý tưởng.

C++ là tất cả về tư duy "có một", một số đã được chuyển đến D và Java. B có phương thứcfoo và điều này quan trọng nhất đối với cả trình biên dịch và lập trình viên - không phải là B là gì. Trong C++, thậm chí có thể redeclare một phương thức như private (hoặc kế thừa class là private) có nghĩa là một thành viên của A sẽ không được hiển thị bởi B.

C# là hardcore về khái niệm "is-a". Vì vậy, bởi vì ở đây B thực sự A, mọi thứ trong B phải giống như trong A. Cả trình biên dịch lẫn lập trình viên đều không phải lo lắng về những thay đổi, bởi vì không có thay đổi nào có thể.B luôn là lựa chọn thay thế hoàn hảo cho A.

Triết lý "is-a" cấm chương trình C# từ công khai thành viên được bảo vệ trước đó, mặc dù nó tầm thường để làm điều đó thông qua trình bao bọc công khai. Nó có ý nghĩa rất ít và chỉ là một sự bất tiện nhỏ ở đây - nhưng nó là một vấn đề lớn trong việc giữ cho triết lý ngôn ngữ nhất quán.

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