как мы можем переопределить метод в дочернем классе, не используя «виртуальный» в родительском классе - PullRequest
3 голосов
/ 03 сентября 2010

Это вопрос интервью.Так возможно ли переопределить метод без виртуального, указанного в родительском методе?

Ответы [ 7 ]

19 голосов
/ 03 сентября 2010

Они, вероятно, хотели, чтобы вы сказали «Используйте ключевое слово new, чтобы скрыть метод». Что технически не переопределяет метод. Если у вас есть

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

class Derived : Base
{
    public new void Bar() { Console.WriteLine("Derived"); }
}

А потом ты написал

Derived derived = new Derived();
derived.Bar();
((Base)derived).Bar();

Вы бы увидели разные результаты. Таким образом, функции, использующие базовый класс, получат результаты для базового метода, а функции, использующие производный класс, получат результаты для нового метода.

4 голосов
/ 03 сентября 2010

Технически вы не можете переопределить метод. Вы можете скрыть это, используя ключевое слово new:

class Foo
{
    public void Bar() {}
}

class FooChild : Foo
{
    new public void Bar() {}
}

Подвох в том, что когда вы вызываете Bar() из базового класса (или если вы приведете FooChild к Foo), он выполнит код базового класса, а не «новый» код.

1 голос
/ 03 сентября 2010

Следующее не переопределяет.Кроме того, пожалуйста, никогда не делайте это по-настоящему.Это «трюк» для обеспечения альтернативного поведения, хотя:

class Base
{
    protected Action m_action;

    public Base()
    {
        m_action = () => Console.WriteLine("Base Class");
    }
    public void NonVirtual()
    {
        m_action();
    }
}

class Derived : Base
{
    public Derived()
    {
        m_action = () => Console.WriteLine("Derived Class");
    }
}

class Program
{
    static void Main (string[] args)
    {
        Base baseClass = new Base();
        Derived derivedClass = new Derived();
        Base derivedAsBase = derivedClass;

        Console.WriteLine("Calling Base:");
        baseClass.NonVirtual();

        Console.WriteLine("Calling Derived:");
        derivedClass.NonVirtual();

        Console.WriteLine("Calling Derived as Base:");
        derivedAsBase.NonVirtual();

        Console.ReadKey();
    }
}

Результат:

Calling Base:
Base Class
Calling Derived:
Derived Class
Calling Derived as Base:
Derived Class

Редактировать: Хотя я и говорю, что это трюк, его можно привести в стратегиюшаблон или аналог.

1 голос
/ 03 сентября 2010

Если бы было возможно переопределение не виртуальных общедоступных методов, у нас были бы гораздо более мощные фреймворки.Нет, невозможно переопределить не виртуальных участников, только скрыть их, используя new ключевое слово .

0 голосов
/ 16 декабря 2013

таким образом, мы можем сделать это, используя новое ключевое слово.

using System;

class Example
{
    static void Main()
    {
        Foo f = new Foo();
        f.M();

        Foo b = new Bar();
        b.M();
    }
}

class Foo
{
    public void M()
    {
        Console.WriteLine("Foo.M");
    }
}

class Bar : Foo
{
    public new void M()
    {
        Console.WriteLine("Bar.M");
    }
}
0 голосов
/ 03 сентября 2010

Нет, это будет скрытие функции.

0 голосов
/ 03 сентября 2010

Ключевое слово «new» может скрывать метод, определенный в базовом классе, когда вы обращаетесь к этому методу через ссылку времени компиляции типа T, такую ​​как typeof (DerivedClass) .IsAssignableFrom (typeof (T)). Вы не можете по-настоящему переопределить это, однако. Ссылки, которые используют базовый тип во время компиляции, всегда будут вызывать базовый метод независимо от того, что вы делаете в определении производного класса.

Если бы мне задали этот вопрос в интервью, я бы так и сказал. Если бы я спрашивал об этом, я бы на это надеялся. Любой, кто думает, что «new» - это то же самое, что и «override», и не определяет свой ответ, каким-то образом не понимает, что означает «virtual» или как работают vtables (концептуально или механически).

...