重新定义子类中的变量类型(即变量隐藏)

时间:2014-12-06 23:12:30

标签: scala

我用几种不同的方式搜索了这些......但还没有找到明确的答案。

class Foo1 { }
class Foo2 extends Foo1 { }

class Bar1 {
    var foo: Foo1 = null
}

class Bar2 extends Bar1 {
    var foo: Foo2 = null  // <-- compiler error
}

错误说:“在类型为test.Foo1的类Bar1中覆盖变量foo;变量foo需要`override'修饰符”但您也不能覆盖var。

在C#中,你可以使用像这样的新关键字

class Foo1 { }
class Foo2 : Foo1 { }

class Bar1
{
    public Foo1 foo = null;
}

class Bar2 : Bar1 
{
    public new Foo2 foo = null;
}

是否可以在Scala中执行此操作?

编辑 - 添加了另一个C#示例来说明我为什么要这样做。

class Foo1 { }
class Foo2 : Foo1 { }

class Bar1
{
    public Foo1 Foo { get { return _foo; } }
    protected Foo1 _foo;
    public Bar1(Foo1 foo) { _foo = foo; }       
}

class Bar2 : Bar1
{
    public new Foo2 Foo { get { return _foo; } }
    protected new Foo2 _foo;
    public Bar2(Foo2 foo) : base(foo) { _foo = foo; }
}

当然,在真正的应用程序中,类和许多成员的方式更复杂,层次结构更深入。

简而言之,它对我的​​作用是它允许我在我的类层次结构中的任何地方使用foo变量而不必使用丑陋的演员表 - 如果我只在声明的单个foo中使用了Bar1班。

谢谢!

2 个答案:

答案 0 :(得分:2)

您似乎正在寻找var属性的协方差。这不会编译,因为它不合理:

class Foo1
class Foo2 extends Foo1 {
  def moo = 42
}
class Foo3 extends Foo1

class Bar1 {
  var foo: Foo1 = null
}

class Bar2 extends Bar1 {
  var foo: Foo2 = null // Let's suppose this compiles
}    

val bar2: Bar2 = new Bar2
val bar1: Bar1 = bar2
bar1.foo = new Foo3
bar2.foo.moo

在最后一行,您在.moo的实例上调用Foo3(它没有实现此类方法),但编译器无法告诉您这一点,因为{{1} }应该是bar2.foo

Foo2然而它编译:

val

更新

经过一些测试和reading this后,我在C#代码中理解的是,class Bar1 { val foo: Foo1 = new Foo1 } class Bar2 extends Bar1 { override val foo: Foo2 = new Foo2 } 实例中确实有2个字段。当被视为Bar2时,Bar1引用x.foo中的字段,并且被视为Bar1Bar2指的是Bar2中的属性。它们的类型甚至它们的性质(方法/字段/类型)可以完全不相关。我无法想到Scala中的任何类似内容。但如果我更正确,您也可以使用x.foo Bar2的其他名称。


更新2

如果永远不会重新分配foo,则可能是您想要的代码:

foo

答案 1 :(得分:2)

这通常表示为类型参数或类型成员。

例如,集合跟踪其基础&#34;表示&#34;或实施:

https://github.com/scala/scala/blob/v2.11.4/src/library/scala/collection/GenSeqLike.scala#L33

它出现在以下的地方:

https://github.com/scala/scala/blob/v2.11.4/src/library/scala/collection/LinearSeqOptimized.scala#L27

但是成员隐藏机制解决的另一个问题是脆弱的类型层次结构。必须为继承设计类(Effective Java)。因此,一个类可以在不考虑与客户端(包括子类)的兼容性的情况下发展的概念具有误导性。

由于私有成员的继承(或不是),Scala中出现了这种情况。我无法随意找到讨论,但in this issue它被称为weird "private members aren't inherited" change。你可能会去,&#34;这有什么奇怪之处?&#34;

This issue可能是伞问题或元bug。

这是令人烦恼的案例:

scala> class A { val v: Int = 42 }
defined class A

scala> class B extends A { private val v: String = "42" }
<console>:8: error: overriding value v in class A of type Int;
 value v has weaker access privileges; it should not be private
       class B extends A { private val v: String = "42" }
                                       ^

有些人主张加强隐私权。