65.9K
CodeProject 正在变化。 阅读更多。
Home

OOP:隐藏(Shadowing)与重写(Overriding)的区别

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.69/5 (12投票s)

2016年2月29日

CPOL

3分钟阅读

viewsIcon

33323

在这篇文章中,我们将通过一个简单的例子来了解 C# 中的阴影概念。

引言

在这篇文章中,我们将讨论使用 C# 的 OOP 中的阴影概念,我们将看到它的工作原理,这将让你了解我们可以在哪里使用它,并且希望你能够在 C# 中进行实际工作时决定它在哪里有用。

什么是阴影 (Shadowing)

阴影是 OOP (面向对象编程) 范例的一个概念。使用阴影,我们可以为基类成员提供一个新的实现,而无需覆盖它,这意味着基类成员的原始实现被派生类中提供的新基类成员实现所阴影 (隐藏)。

假设您有一个外部程序集,您已将其添加到您的项目中。该程序集中有一个类,它有一个未定义为 virtual 的方法,并且您想在派生类中覆盖该方法 (为该方法定义您自己的实现)。 你会怎么做?

这是您可以使用阴影概念在派生类中覆盖方法的情况。

定义

以下是它的一些定义。

根据 MSDN

  • 阴影实际上是在面向对象编程中使用多态的一种概念。当两个编程元素共享相同的名称时,其中一个可以隐藏或阴影另一个。在这种情况下,阴影元素不可用于引用;相反,当您的代码使用元素名称时,编译器会将其解析为阴影元素。
  • 阴影实际上是在派生类中隐藏重写方法的实现,并使用派生类对象调用父类实现

重写 (Overriding) 和阴影 (Shadowing) 之间的区别

阴影和重写之间存在一个主要区别,通常当我们重写派生类中的 virtual 方法并创建派生类的实例时,然后如果我们以基类对象的形式保持对派生类对象的引用,并调用该成员,它总是调用应该发生的派生类实现,但在阴影中情况不同,如果对于同一个 virtual 成员,我们在派生类中使用 new 关键字来阴影它,并且我们像上面一样调用该实现,当我们引用基类类型的对象时,它将调用基类实现,如果我们引用相同派生类型的对象,它将调用派生类型实现,因此基类和派生类实现相互隐藏,要调用的实现的方法取决于我们是使用基类型还是派生类型的引用来调用该成员。

示例

假设我有一个基类 BaseLogger 它有两个 virtual 方法(意味着它们可以在子类中被重写)定义
public abstract class BaseLogger
{
    public virtual void Log(string message)
    {
        Console.WriteLine("Base: " + message);
    }

    public virtual void LogCompleted()
    {
        Console.WriteLine("Completed");
    }
}

现在我创建一个从 BaseLogger 类继承的 Logger 类。Logger 类如下所示

public class Logger : BaseLogger
{
    public override void Log(string message)
    {
        Console.WriteLine(message);
    }

    public new void LogCompleted()
    {
        Console.WriteLine("Finished");
    }
}

现在我希望我的控制台打印以下行

Log started!

Base: Log Continuing
 
Completed

我应该在主程序中写什么来获得上面的输出? 这是我们需要编写的代码

public class Program
{
    public static void Main()
    {
        BaseLogger logger = new Logger();

        logger.Log("Log started!");
        logger.Log("Base: Log Continuing");
        logger.LogCompleted();
    }
}

第一次调用 Log 方法是可以的,它已经调用了 Derived Logger 类的 Log 方法,这是应该的,因为我们已经在 Logger 类中重写了它。

第二次调用也是一样的。

现在请注意第三次调用,它已经调用了基类 LogCompleted() 方法而不是派生类,这是因为我们使用 new 关键字定义了派生类方法,当我们使用 BaseLogger 类型的对象调用它时,它会隐藏派生类方法,BaseLogger 是我们的基类,如果我们没有放置 new 关键字,编译器会认为该方法正在被隐藏或阴影化,并且当您编译它时,它会显示一个警告,说明

引用

如果打算隐藏,请使用 new 关键字

如果我们想调用派生类 LogCompleted() 方法,我们的对象引用应该属于 Logger 类型,而不是 BaseLogger 类型,而在方法重写中,情况并非如此。

在方法重写中,如果我们把派生类的对象转换为基类并调用方法,它会调用派生类的重写实现。

© . All rights reserved.