访问基类的受保护成员

3
我是一个有用的助手,可以进行文本翻译。
我不经常使用继承,所以我不太确定为什么它无法工作。在我的项目中,我有以下内容:
带有受保护成员变量的基础封闭类:
sealed class TheRoot {
  protected def some: String = "TheRoot"
}

并且它有一些逻辑的后代:

final case class Descendant() extends TheRoot {
  def call: Unit = { 
    val self: TheRoot = this
    self.some // <<- throw compilation error
  }
}

编译以上代码会给我以下错误:
error: method some in class TheRoot cannot be accessed in TheRoot
 Access to protected method some not permitted because
 prefix type TheRoot does not conform to
 class Descendant where the access take place
           self.some

我不太确定从超类调用受保护成员的问题在哪里...但如果将其封装到伴生对象中,它就会变得更有趣:它神奇地解决了这个问题:

sealed class TheRoot {
  protected def some: String = "TheRoot"
}

object TheRoot {
  final case class Descendant() extends TheRoot {
    def call: Unit = {
      val self: TheRoot = this
      self.some // <<- NO ERROR!
    }
  }
}


// Exiting paste mode, now interpreting.

defined class TheRoot
defined object TheRoot
1个回答

1

文档所述

与Java相比,访问受保护的成员也更加严格。在Scala中,受保护的成员只能从定义该成员的类的子类中访问。在Java中,这样的访问也可以来自同一包中的其他类。在Scala中,有另一种方法可以实现此效果,如下所述,因此保护可以保持不变。所示例子说明了受保护的访问:

 package p {
  class Super {
    protected def f() { println("f") }
  }
  class Sub extends Super {
    f()
  }
  class Other {
    (new Super).f()  // error: f is not accessible
  }
}

在您的代码中,如果将 self.some 更改为 some,那么就可以了。
同时,伴生对象可以访问其伴生类的任何成员,因此 TheRoot 对象的 Descendant 可以访问 some 的受保护方法。

我需要将当前对象的类型向上转换,我的示例已经简化了。在您的报价中,您还提到“受保护的成员只能从类的子类访问”,这就是我询问的原因,对我来说,“Descendant”是“TheRoot”的子类。我知道伴生对象的机制,但我不清楚为什么它在这种情况下允许受保护的访问。 - 4lex1v
你为什么需要将this向上转型到超类型?你可以在任何接受该子类型的地方使用该子类型(当然除了逆变参数)... 无论如何,将你的受保护成员作用域限定在封闭包中(protected[p] def some: String = ...),就像在对象中封闭Descendant一样也能起作用。 - Sergey
@4lex1v 抱歉,之前我误解了你的问题。我发现另一件奇怪的事情。this.some 可以工作,但 self.some 不行。 - Jerry

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