Полиморфизм / Перекрытие - PullRequest
5 голосов
/ 12 января 2012

Может кто-нибудь объяснить, в чем разница между этими двумя примерами?

Класс A

protected virtual string GetData()

Класс B

private override string GetData()

И следующее:

Класс A

protected string GetData()

Класс B

private string GetData()

Предполагая, что класс B наследуется от класса A.

Я всегда предполагал, что вам нужно использовать virtual в суперклассе и override вподкласс, если вы хотите переопределить метод, однако я попытался удалить ключевые слова, и программа скомпилирована нормально.В чем именно разница, если есть?

Ответы [ 3 ]

5 голосов
/ 12 января 2012

Второй пример, который вы показали, скрывает GetData родителя, он не переопределяет его.

Пример:

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

Он выводит:

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()

На самом деле этот пример недопустим, потому что он должен использовать ключевое слово new в public new void Test2() в классе Derived.

Он работает так же, как перегрузка операторов.Это на самом деле ничего не отменяет.Когда у вас есть точный тип Derived, он вызывает новый метод.

Вы должны быть очень осторожны с сокрытием членов, это совсем не похоже на переопределение (классы) или реализацию (интерфейсы) вообще.Только если у вас есть тип точный , он вызовет метод new , в противном случае он по-прежнему будет вызывать метод базового типа!

3 голосов
/ 12 января 2012

Разница в том, что в первом случае вы переопределяете, а во втором случае вы прячетесь, что совершенно другое.

В первом случае:

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

В другомhand во втором случае:

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

Во втором случае вы просто скрываете реализацию A GetData (), но вы всегда сможете вызвать реализацию A через переменную типа A, даже если переменная ссылается наэкземпляр типа B. Обратите внимание, что это полностью отличается от поведения переопределения.

0 голосов
/ 12 января 2012
public class A
{
    public virtual string GetData() { return "A";}
}

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

Что вы ожидаете, если используете классы, как в следующем кодовом блоке?

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

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

Будет напечатано «A», «B», «B». Переменная c хранится как тип A, но при выполнении метода код разрешается в «реальной» реализации. (см. Google для виртуальной таблицы функций и принципа разрешения)

Если вы не используете виртуальные и переопределить, как в коде ниже, это выведет «A», «B», «A».

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

public class B : A
{
    public new string GetData() { return "B"; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...