为什么我可以使用abstract override来重写一个抽象方法?

11

我有一个抽象基类:

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()。就我所知,它是多余的 - 我相当确定删除它不会产生任何负面影响。

是否存在某些用例可以对抽象类上的抽象覆盖执行有用操作?如果没有,为什么没有编译器警告提示我的代码无效?


1
这个链接可能会有帮助 - http://msdn.microsoft.com/zh-cn/library/ms173150(VS.80).aspx - terrybozzio
3
这属于"因为规范这么说"的范畴。 - Eric J.
看起来这是一个很好的Roslyn功能请求。 - Federico Berasategui
2个回答

3

为什么我可以使用抽象关键字重写一个抽象方法?

实际上,并没有阻止这样做的实际理由。如果它会产生编译错误,那么它只会使类更加脆弱。例如:

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

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

如果在抽象类上使用抽象覆盖是不合法的,将Foo上的DoSomeStuff更改为抽象将阻止Bar编译。 抽象覆盖是多余的,但没有潜在的负面影响,所以编译器可以接受。
为什么没有编译器警告告诉我我写的东西什么也没做?
编译器会为某些表示风险的事情产生警告:非显式方法隐藏,无法访问的代码,使用过时的方法等。 一个不必要的抽象覆盖可能表明的唯一“问题”是代码编写效率不高。 这不是编译器关心的事情。
在抽象类上使用抽象覆盖有用的用例吗?
从功能上讲没有。 但是,有一些用例您可能会故意这样做:
- 提高代码的“可读性”。 有冗余的抽象覆盖将作为提醒该方法是抽象的。 - 如果将来更改基类包括提供虚拟实现,则可以预先防止某些类访问该基类。 - 如果抽象覆盖是多余的,因为基类已从虚拟实现更改为抽象,则可以安全地保留它。

2

通过在Bar中显式地进行abstract override,您可以确保即使在将来的Foo中它可能被更改为非抽象方法,它也会被Bar的后代视为抽象方法。尽管发生了这样的变化,Bar的后代仍将使用相同的合同。


我认为这样做有实际价值,但它不违反 Liskov 替换原则吗?任何操作 Foo 并期望具体的 DoSomeCrazyStuff 的方法在传递 Bar 时都会出现问题。 - Austin Mullins
2
@AustinMullins Bar和DoSomeCrazyStuff仍然是抽象的,因此没有任何东西会在Bar上运行,而是一个具体的类,如果没有所有抽象方法的实现,它将无法编译。 - User
@OndrejTucny 不需要额外的抽象重写来保护免受合同更改的影响,Bar 的现有重写将仍然覆盖虚拟实现。它是预防性地防止 Foo 更改为虚拟后编写的 Bar 子类访问基础实现。为什么要阻止访问尚未编写的方法?为什么不在实际编写该方法之前再做决定呢? - User

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接