【问题标题】:Why can I abstract override an abstract method?为什么我可以抽象覆盖抽象方法?
【发布时间】:2014-09-12 04:21:39
【问题描述】:

我有一个抽象基类:

abstract class Foo
{
    virtual void DoSomeStuff()
    {
        //Do Some Stuff
    }

    abstract void DoSomeCrazyStuff();
}

还有一个由此派生的抽象类:

abstract class Bar : Foo
{
    abstract override void DoSomeStuff();

    abstract override void DoSomeCrazyStuff();
}

我理解您为什么要抽象覆盖 DoSomeStuff() - 这将需要为进一步的派生类提供新的实现。但我不明白你为什么要抽象覆盖DoSomeCrazyStuff()。据我所知,它是多余的 - 我很确定删除它会产生零负面影响。

是否存在一些用例,其中抽象的抽象覆盖会做一些有用的事情?如果没有,为什么没有编译器警告告诉我我写的东西什么都不做?

【问题讨论】:

标签: c#


【解决方案1】:

为什么我可以抽象覆盖抽象方法?

首先,没有实际理由阻止它。如果它产生了编译器错误,那只会使类变得更脆弱。例如:

abstract class Foo
{
    virtual void DoSomeStuff()
    {
        //Do Some Stuff
    }
}

abstract class Bar : Foo
{
    abstract override void DoSomeStuff();
}

如果 abstract 上的 abstract 覆盖是非法的,现在将 Foo 上的 DoSomeStuff 更改为 abstract 将阻止 Bar 编译。抽象覆盖是多余的,但没有潜在的负面影响,因此编译器可以接受。


为什么没有编译器警告告诉我我写的东西什么都不做?

编译器会针对某些代表风险的事情产生警告:非显式方法隐藏、无法访问的代码、使用过时的方法等。不必要的抽象覆盖可能表明的唯一“问题”是代码没有有效地编写。这不是编译器关心的事情。


是否存在一些用例,其中抽象上的抽象覆盖会做一些有用的事情?

没有功能。但是,在一些用例中您可能会故意这样做:

  • 提高代码的“可读性”。具有冗余抽象覆盖将提醒该方法是抽象的。
  • 如果未来对基类的更改包括提供虚拟实现,您可以先发制人地阻止某些类访问该基类。
  • 如果抽象覆盖是多余的,因为基类已从虚拟实现更改为抽象,则可以放心地保留它。

【讨论】:

    【解决方案2】:

    通过在Bar 中明确地abstract overrideing 它,您可以确保Bars 的后代将其视为抽象,即使将来在Foo 中它可能会更改为非抽象的。尽管有这样的变化,Bars 的后代将使用相同的合同。

    【讨论】:

    • 我看到了它的实用价值,但这不是违反里氏替换吗?任何在Foo 上运行并期望具体DoSomeCrazyStuff 的方法在传递Bar 时都会中断。
    • @AustinMullins Bar 和 DoSomeCrazyStuff 仍然是抽象的,因此不会在 Bar 上运行任何内容,而是在没有实现所有抽象方法的情况下无法编译的具体类。
    • @OndrejTucny 您不需要额外的抽象覆盖来防止合同更改,Bar 的现有覆盖仍然会覆盖虚拟实现。它是先发制人地防止在Foos 更改为虚拟后写入的Bar 的后代访问基本实现。为什么要阻止访问尚未编写的方法?为什么不保存该决定,直到实际编写该方法?
    猜你喜欢
    • 1970-01-01
    • 2013-09-12
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    • 2022-08-18
    • 1970-01-01
    相关资源
    最近更新 更多