Точная разница между overriding и hiding

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

class A
{
    public virtual void Test1() { //Impl 1}
    public virtual void Test2() { //Impl 2}
}
class B  : A
{
    public override void Test1() { //Impl 3}
    public new void Test2() { Impl 4}
}

static Main()
{
    A aa=new B() //This will give memory to B
    aa.Test1(); //What happens in terms of memory when this executes
    aa.Test2(); //-----------------------SAME------------------------
}

здесь память с классом B, но во втором операторе aa.Условие_2 будет вызван метод класса A. Почему? Если B имеет память, то метод B должен быть вызван (с моей точки зрения).

любая ссылка / упражнение, которое описывает этот фундаментальный очень глубоко и полностью, будет большой помощью.

9 ответов


посмотри это ответ на другой вопрос Эрик Липперт.

перефразируя (в пределах моего понимания) эти методы уходят в "слоты". A имеет два слота: один для Test1 и Test2.

С A.Test1 помечен как virtual и B.Test1 помечен как override, С Test1 не создает свой собственный слот, но перезаписывает 'ы. Относитесь ли вы к экземпляру B как B или бросьте его в A, та же реализация находится в этом слоте, поэтому вы всегда получаете результат B.Test1.

по сравнению с B.Test2 отмечается new, он создает свой собственный new слот. (Как было бы, если бы он не был отмечен new но ему дали другое имя.) с Test2 по-прежнему" там " в своем слоте; он был скрыт, а не перезаписан. Если вы обрабатываете экземпляр B как B, вы получаете B.Test2; если вы бросите его в A, вы не можете посмотреть новый слот, и A.Test2 вызывается.


добавить @Роулинг это практические примеры могут быть показаны на примере таких, как этот:

class Base
{
    // base property
    public virtual string Name
    {
        get { return "Base"; }
    }
}

class Overriden : Base
{
    // overriden property
    public override string Name
    {
        get { return "Overriden"; }
    }
}

class New : Base
{
    // new property, hides the base property
    public new string Name
    {
        get { return "New"; }
    }
}

1. Переопределение

в случае overriden свойство, слот виртуального метода базового класса заменить другой реализацией. Компилятор видит метод как виртуальный, и должен разрешить его реализацию во время выполнения с помощью виртуального объекта таблица.

{
    Base b = new Base();
    Console.WriteLine(b.Name); // prints "Base"

    b = new Overriden();
    // Base.Name is virtual, so the vtable determines its implementation
    Console.WriteLine(b.Name); // prints "Overriden"

    Overriden o = new Overriden();
    // Overriden.Name is virtual, so the vtable determines its implementation
    Console.WriteLine(o.Name); // prints "Overriden"
}

2. Прячется!--15-->

когда метод или свойство скрытый С помощью new ключевое слово, компилятор создает новый non-virtual метод только для производного класса; метод базового класса остается нетронутым.

если тип переменной Base (т. е. содержит только виртуальный метод), его реализация будет решен через vtable. Если тип переменной New, тогда будет вызван не виртуальный метод или свойство.

{
    Base b = new Base();
    Console.WriteLine(b.Name); // prints "Base"

    b = new New();
    // type of `b` variable is `Base`, and `Base.Name` is virtual,
    // so compiler resolves its implementation through the virtual table
    Console.WriteLine(b.Name); // prints "Base"

    New n = new New();
    // type of `n` variable is `New`, and `New.Name` is not virtual,
    // so compiler sees `n.Name` as a completely different property
    Console.WriteLine(n.Name); // prints "New"
}

3. Резюме

если часть вашего кода принимает базовый тип, она будет всегда использовать виртуальную таблицу во время выполнения. Для большинства сценариев ООП это означает, что маркировка метода как new очень похоже на то, чтобы дать ему совершенно другое имя.

4. Размеры объектов после создания экземпляра

обратите внимание, что создание экземпляра ни один из этих типов не создает копию виртуальной таблицы. Каждый объект .NET имеет пару байтов заголовка и указатель на виртуальную таблицу таблицы его типа (class).

о new property (тот, который не является виртуальным), он в основном компилируется как статический метод с семантикой thiscall, что означает, что он также ничего не добавляет к размеру экземпляра в памяти.


уже отвечала на здесь

переопределение - это определение нескольких возможных реализаций одной и той же сигнатуры метода, так что реализация определяется типом времени выполнения нулевого аргумента (обычно идентифицируется именем this В C#).

прячась определение метода в производном типе, с подписью, идентичной той, которая в один из его базовых типов без основной.

на практическая разница между переопределением и прячась следующим образом:

скрытие для всех других членов (статические методы, члены экземпляра, статические члены). Он основан на ранней привязке . Более ясно, что метод или элемент, который будет вызываться или использоваться, решается во время компиляции.

•Если метод переопределен, реализация для вызова основана на типе времени выполнения аргумента this. •Если метод просто скрыт, реализация для вызова основана на типе времени компиляции аргумента this.

вот некоторые примеры : Пример 1. и Пример # 2


метод Test1 () в классе A и метод test1 () в классе B будут выполняться в соответствии с MethdOverriding.

метод Test2 () в классе A и метод test2 () в классе B будут выполняться в соответствии с Способ Сокрытия.

методом переопределение дочерние члены класса будут выполняться, и в Способ Сокрытия будут выполняться члены родительского класса.


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

// base
    public int GrossAmount { get; set; }

    // hiding base
    public new string GrossAmount
    {
        get;
        set;             
    }

вычитание из кода при условии, что вы должны иметь B:A.

вы можете скрыть метод в случае, если вы хотите создать свою собственную реализацию метода (скажем) базового класса, который не может быть переопределенным, потому что, скажем, это не virtual.

в моем опыте, я использовал прячась в основном для debug целей.

например, когда я не знаю, кто устанавливает свойство некоторого 3rd prt component, которым код не доступный мне. Вот что я делаю:--10-->

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

иногда, очень полезно и помогает мне быстро получить информацию, особенно на первом этапе, когда вы изучаете новые components, frameworks, libraries.. что угодно.


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


 public class BaseClass
    {
      public void PrintMethod()
      {
       Console.WriteLine("Calling base class method");
      }
     }
     public class ChildClass
     {
      public new void PrintMethod()
      {
       Console.WriteLine("Calling the child or derived class method");
       }
      }
      class Program
      {
       static void Main()
       {
        BaseClass bc = new ChildClass();
        bc.PrintMethod();
        }
       }

метод скрытия-это когда ссылочная переменная базового класса указывает на объект дочернего класса. Он вызовет метод hidden в базовом классе.

где as, когда мы объявляем виртуальный метод в базовом классе. Мы переопределяем этот метод в производном или дочернем классе. Затем ссылочная переменная базового класса вызовет метод производного класса. Это называется переопределением метода.


class Base {
    int a;
    public void Addition() {
        Console.WriteLine("Addition Base");
    }
    public virtual void Multiply()
    {
        Console.WriteLine("Multiply Base");
    }
    public void Divide() {
        Console.WriteLine("Divide Base");
    }
}

class Child : Base
{
    new public void Addition()
    {
        Console.WriteLine("Addition Child");
    }
    public override void Multiply()
    {
        Console.WriteLine("Multiply Child");
    }
    new public void Divide()
    {
        Console.WriteLine("Divide Child");
    }
}
class Program
{        
    static void Main(string[] args)
    {
        Child c = new Child();
        c.Addition();
        c.Multiply();
        c.Divide();

        Base b = new Child();
        b.Addition();
        b.Multiply();
        b.Divide();

        b = new Base();
        b.Addition();
        b.Multiply();
        b.Divide();
    }
}

выход : -

Кроме Ребенка

Умножить Ребенок

Разделить Детей

Дополнение Базы

Умножить Ребенок

Разделить Базы

Дополнение Базы

Умножить Базы

Разделить Базы

во время переопределения компилятор проверяет объект класса, но в в скрытии компилятор проверяет только ссылку на класс