什么是影子?

34 c# polymorphism shadowing

在C#中,阴影一词是什么意思?我已阅读此链接,但并未完全理解.

Jim*_*hel 45

阴影隐藏基类中的方法.使用您链接的问题中的示例:

class A 
{
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A
{
   public new int Foo() { return 1;}
   public override int Bar() {return 1;}
}
Run Code Online (Sandbox Code Playgroud)

B 会覆盖虚方法Bar.它隐藏(阴影)非虚方法Foo.覆盖使用override关键字.阴影是使用new关键字完成的.

在上面的代码中,如果在类中定义方法时没有使用new关键字,则会收到此编译器警告:FooB

'test.B.Foo()' hides inherited member 'test.A.Foo()'. Use the new keyword if hiding was intended.
Run Code Online (Sandbox Code Playgroud)

  • @ sab669:想象一下,你想"覆盖"一个非虚方法.你实际上无法覆盖它,所以你要遮蔽它.它不是一个完美的解决方案,因为它在所有情况下都不像重写的虚拟方法,但是当从派生类调用时,它将按预期工作.你想要这样做是相对罕见的,但是当你需要它时,你真的需要它. (3认同)

Ken*_*art 32

  • 覆盖:重新定义基类上的现有方法
  • 阴影:使用与基类中相同的签名创建一个全新的方法

  • 请注意,使用阴影可以更改返回类型. (5认同)

mqp*_*mqp 21

假设我有一个实现虚方法的基类:

public class A
{
    public virtual void M() { Console.WriteLine("In A.M()."); }
}
Run Code Online (Sandbox Code Playgroud)

我还有一个派生类,它也定义了一个方法M:

public class B : A
{
    // could be either "new" or "override", "new" is default
    public void M() { Console.WriteLine("In B.M()."); }
}
Run Code Online (Sandbox Code Playgroud)

现在,假设我写了一个这样的程序:

A alpha = new B(); // it's really a B but I cast it to an A
alpha.M();
Run Code Online (Sandbox Code Playgroud)

对于我希望如何实现,我有两种不同的选择.默认行为是调用A的M版本.(这与将" new"关键字应用于的行为相同B.M().)

当我们有一个具有相同名称但从基类调用时具有不同行为的方法时,这称为"阴影".

或者,我们可以指定" override" B.M().在这种情况下,alpha.M()会调用B的版本M.


Jor*_*oba 10

阴影包括在子类中隐藏具有新定义的基类方法.

隐藏和覆盖之间的区别与调用方法的方式有关.

这样,当重写虚方法时,基类的方法调用表的调用地址将替换为子例程的地址.

另一方面,当隐藏方法时,会将新地址添加到子类的方法调用表中.

当调用相关方法时:

  1. 获取方法调用表类类型,如果我们使用对基类的引用进行调用,则获取基类方法表,如果我们有对子类的引用,则获取子类方法表.
  2. 在表中搜索该方法,如果找到则进行调用,否则搜索基类方法表.

如果我们通过引用子类来调用该方法,那么行为是相同的,如果方法已被重写,则方法地址将在基类中找到,如果方法被隐藏,则方法地址将在子类,并且由于已经找到,因此不会搜索基类表.

如果我们通过引用基类来调用该方法,那么行为会发生变化.覆盖时,当方法地址覆盖基类条目时,即使持有对基类的引用,我们也会调用子方法.使用阴影时,基类方法表(它是我们持有对基类的引用时唯一可见的)包含虚方法地址,因此将调用基类方法.

通常,阴影是一个坏主意,因为它会根据我们对它的引用引入实例行为的差异.


Jar*_*Par 8

扩展肯特的正确答案

当消除何时调用哪种方法的歧义时,我喜欢考虑阴影与覆盖以下内容

  • 阴影:调用的方法取决于调用点的引用类型
  • 覆盖:调用的方法取决于调用时对象的类型.