【发布时间】:2020-11-09 13:30:57
【问题描述】:
首先,我意识到用子类中的抽象方法覆盖超类中的具体方法没有多大意义。但是......因为在 Scala 中实际上可以做到这一点,所以我尝试了以下 sn-p,结果让我感到困惑。
第一个场景
- 在超超类中被重写的具体方法
- 抽象方法在超类中
class A {
def x: String = "A"
}
abstract class B extends A {
def x: String
}
class C extends B {
def x: String = "C"
}
在 scala REPL 中执行上面的 sn-p 会导致以下错误:
def x: String = "C"
^
<pastie>:10: error: `override` modifier required to override concrete member:
def x: String (defined in class A)
现在的问题是:为什么类B 中的抽象方法似乎被忽略了?但是,如果从定义中删除 C.x,B.x 确实会产生影响。因为下面的sn-p也编译不了。
class A {
def x: String = "A"
}
abstract class B extends A {
def x: String
}
class C extends B
导致以下错误
class C extends B
^
<pastie>:9: error: class C needs to be abstract. No implementation found in a subclass for deferred declaration
def x: String (defined in class B)
第二种情况
- 在超类中被重写的具体方法
- 抽象方法在 trait 中
class A {
def x: String = "A"
}
trait B {
def x: String
}
class C extends A with B
尝试实例化C,
scala> (new C).x
val res0: String = A
看起来B.x 抽象方法刚刚被编译器忽略了。
更新
在我的问题的第一版中,我愚蠢地忘记了在 第二个场景 中扩展 A,这导致了一个错误的结论,即类和特征在我的示例中表现不同。对于我的疏忽,我深表歉意。
让我试着重新提出我的问题:
在第一种和第二种情况下,抽象B.x在类层次结构中间的作用是什么?
据我了解,通过继承和方法解析顺序 (MRO),
- 在第一种情况下
B.x覆盖A.x和C.x覆盖B.x。由于B.x是抽象的,当C.x实现B.x时,不需要指定override修饰符。 - 在第二种情况下,
B.x覆盖A.x和C没有实现抽象B.x。所以C应该是抽象的,不能编译。
但在我看来,编译器只是忽略了类层次结构中间的抽象方法B.x。这种行为是在语言规范中的某个地方定义的,还是完全出乎意料和意外(并且只是一个编译器错误)?
【问题讨论】:
标签: scala