2012-05-05 1 views
6

Я программист C#, новый для языка D. Я немного запутался с ООП на языке программирования D.Почему функция с защищенным модификатором может быть переопределена и доступна где угодно?

Если предположить, что у меня есть следующий класс:

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

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

protected модификатора означает, что я могу получить доступ к методу .foo() только на унаследованном классе, так почему это D программы компилируется нормально?

Вот эквивалент 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(); 
    } 
}; 

Это не компилирует и учитывая следующее сообщение об ошибке (как я ожидал):

test.cs (10 , 30): ошибка CS0507: B.foo()': cannot change access modifiers when overriding защищен 'наследуется членом `A.foo()'

Может кто-нибудь объяснить это поведение D? Заранее спасибо.

+2

Почему вы смущены? C# и D - это просто разные языки, поэтому они делают что-то по-другому. На первый взгляд, оба подхода имеют для меня какой-то смысл, поэтому разработчикам языка решать, в какую сторону идти. – svick

+0

Humm, потому что я имел в виду, что модификаторы доступа объектно-ориентированного языка программирования работают одинаково. – Jack

+0

downvotes- можете объяснить пожалуйста? – Jack

ответ

16

Нет никакой цели в предотвращении переопределения. Полученный класс может реализовать тривиальную функцию пересылки, которая позволяет получить доступ. Рассмотрим:

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! 
    } 
}; 

Таким образом, несмотря на то, что я не переопределять уровень доступа foo, я до сих пор разрешен доступ общественности к нему и нет ничего, что вы можете с этим поделать. Разрешить переопределение просто проще.

+0

Humm, тогда это 'D' дизайнер. На языке 'C# .NET' невозможно написать что-то вроде метода' call_foo() '. Он дал «ошибку CS0122: A.foo()» недоступен из-за уровня защиты. «Спасибо вам за ответ. :) – Jack

+0

@Jack: Что, на C# вы не можете написать общедоступный метод, который вызывает защищенный метод? – Puppy

+0

№ Не работает для меня, я тестировал на C# -Mono и дал приведенное выше сообщение об ошибке. – Jack

5

Поведение D в этом соответствует поведению Java. Производный класс может дать своей функции уровень доступа, который является менее ограничительным, чем тот, который используется для функции базового класса, но не более ограничительный. Таким образом, функция protected может быть переопределена либо как protected, либо public, но она не может быть переопределена как private, а функция public может быть переопределена только как public.

Я понятия не имею, почему C# ограничивает protected так, что вы не можете переопределить его функцией public. Как кто-то, кто много программировал на C++, D и Java, но очень немного в C#, выбор C# здесь имеет очень мало смысла для меня. C + +, D и Java все это позволяют.

7

Потому что есть несколько отличных ответов на вопрос «почему это возможно?». Я думаю, что C# заслуживает объяснения, почему это НЕ возможно: речь идет о «философии» языкового дизайна и может быть сведена к «is-a» против «имеет» столкновение идей.

C++ все о мышлении «есть-а», некоторые из них были переданы D и Java. B имеет метод foo, и это наиболее важно как для компилятора, так и для программиста - не то, что B. В C++ можно даже переопределить метод как частный (или наследовать класс как закрытый), что означает, что член A НЕ будет открыт B.

C# - хардкор о концепции «is-a». Поэтому, поскольку здесь B фактически A, все в B должно быть точно таким же, как в A. Ни компилятор, ни программист не должны беспокоиться об изменениях, потому что никаких изменений не возможно.B всегда является идеальной заменой для A.

Философия «is-a» запрещает программе C# публиковать ранее защищенный элемент, хотя это тривиально делать через общедоступную оболочку. Это мало смысла, и это всего лишь небольшое неудобство здесь, но это очень важно в том, чтобы придерживаться философии языка.