Точная разница между переопределением и скрытием
Кто-нибудь может сказать, что работает над переопределением и скрытием с точки зрения памяти и ссылок.
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.Test2. Почему это? Если B имеет память, тогда следует называть метод B (с моей точки зрения).
Любая ссылка/упражнение, которая описывает это фундаментальное очень глубоко и полностью, будет большой помощью.
Ответы
Ответ 1
Взгляните на этот ответ на другой вопрос Эрика Липперта.
Перефразируя (до пределов моего понимания), эти методы переходят в "слоты". A
имеет два слота: один для Test1
и один для Test2
.
Так как A.Test1
помечен как virtual
, а B.Test1
отмечен как override
, B
реализация Test1
не создает свой собственный слот, а перезаписывает реализацию A
. Если вы рассматриваете экземпляр B
как B
или отбрасываете его на A
, такая же реализация находится в этом слоте, поэтому вы всегда получаете результат B.Test1
.
В отличие от этого, поскольку B.Test2
отмечен new
, он создает свой собственный новый слот. (Как если бы он не был помечен new
, но ему было присвоено другое имя.) A
реализация Test2
по-прежнему "существует" в своем собственном слоте; он был скрыт, а не перезаписан. Если вы обрабатываете экземпляр B
как B
, вы получаете B.Test2
; если вы добавили его в A
, вы не сможете увидеть новый слот, а A.Test2
вызывается.
Ответ 2
Чтобы добавить к @Rawling answer, практические примеры можно было бы показать с помощью примера, например:
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. Скрытие
Когда метод или свойство скрыто с использованием ключевого слова new
, компилятор создает новый не виртуальный метод только для производного класса; метод базового класса остается нетронутым.
Если тип переменной 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
(тот, который не является виртуальным), он в основном скомпилирован как статический метод с семантикой thiscall, что означает, что он также ничего не добавляет к размеру экземпляра в памяти.
Ответ 3
Уже ответил на здесь
Переопределение - это определение множества возможных реализаций одной и той же сигнатуры метода, так что реализация определяется типом среды нулевого аргумента (обычно обозначается именем this на С#).
Скрытие - это определение метода в производном типе с сигнатурой, идентичной сигнатуре в одном из базовых типов без переопределения.
Практическая разница между переопределением и скрытием выглядит следующим образом:
Скрытие для всех остальных членов (статические методы, члены экземпляра, статические члены). Он основан на раннем связывании. Более четко, метод или член, который будет вызываться или используется, определяется во время компиляции.
• Если метод переопределен, реализация для вызова основана на типе времени выполнения аргумента this.
• Если метод просто скрыт, реализация для вызова основана на типе времени компиляции аргумента.
Вот несколько примеров: Пример # 1. и Пример # 2
Ответ 4
Метод Test1() в классе A и методе test1() в классе B будет выполняться в соответствии с MethdOverriding.
Метод Test2() в классе A и методе test2() в классе B будет выполняться в соответствии с Скрытием метода.
В методе Переопределение будут выполняться элементы дочернего класса, а в Скрытие метода будут выполняться члены класса родителя.
Ответ 5
Вычитая из предоставленного кода, вы должны иметь B:A
.
Вы можете скрыть метод в случае, если вы хотите создать свою собственную реализацию метода (скажем) базового класса, который нельзя переопределить, вызывать, скажем, не virtual
.
В моем опыте я использовал главным образом для целей debug
.
Например, когда я не знаю, кто задает свойство некоторого 3-го prt component
, какой код мне недоступен. Итак, что я делаю:
- создать дочерний класс из компонента
- скрыть свойство, представляющее интерес, с ключевым словом
new
- установите точку останова в
set
- и подождите, когда он будет удален.
Иногда, очень полезно и помогает мне быстро получать информацию, особенно на первом этапе, когда вы изучаете новые components
, frameworks
, libraries
.. что угодно.
Ответ 6
Проще говоря, при переопределении метода или свойства метод переопределения должен иметь ту же подпись, что и базовый метод. При скрытии это не требуется, новый объект может принимать любую форму, как показано ниже.
// base
public int GrossAmount { get; set; }
// hiding base
public new string GrossAmount
{
get;
set;
}
Ответ 7
Скрывая метод или свойство, вы просто заявляете, что хотите, чтобы этот метод был полиморфным, когда у вас есть объект этого типа. Кроме того, скрытые методы вызывают не полиморфным способом, поэтому вызов этого типа метода должен быть известен во время компиляции, поскольку это был просто не виртуальный метод.
Ответ 8
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();
}
}
Скрытие метода заключается в том, что если базовая переменная базового класса указывает на объект дочернего класса. Он будет вызывать скрытый метод в базовом классе.
Где as, Когда мы объявляем виртуальный метод в базовом классе. Мы переопределяем этот метод в производном или дочернем классе. Затем базовая переменная базового класса вызовет метод производного класса. Это называется переопределением методов.
Ответ 9
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();
}
}
Выход: -
Дополнение ребенка
Умножить ребенка
Разделить ребенка
База дополнений
Умножить ребенка
Разделить базу
База дополнений
Умножить базу
Разделить базу
Во время переопределения компилятор проверяет объект класса, но в
в скрытии компилятора проверяет только ссылку класса