继承和特质

3

我从另一个问题中找到了这篇文章:

“[...] 一个扩展类的特质会对可以扩展该特质的类做出限制 - 也就是说,所有混入该特质的类都必须扩展该类”

以下是一个小例子:

class C 
trait U
trait T extends C 

class D extends U with T // does not work
class E extends T with U // works

显然,当特征从类继承时,您必须将特征放在您原本会放置类的位置(即直接在 extends 后面)

现在是我的问题:

(扩展前面的示例)

class C 
class Test
trait U
trait T extends C 
trait Tst extends Test


class D extends U with T // does not work
class E extends T with U // works
class Test2 extends Tst with T
  • 当我们想从两个不同的 traits 继承时,每个 traits 都继承自不同的类,我们该怎么办?(请参见 Test 2 类)这似乎是不可能的。
  • 如果我们需要注意扩展类的 traits 的位置,那么 traits 是如何工作的呢?从类继承的 traits 不再是“正常”的 traits 吗?

2
我觉得类继承特征有点奇怪。你有没有一个具体的例子来说明为什么这是必要的? - Yuval Itzchakov
不幸的是,我没有。我只是在一个例子中看到过,并且自己也很好奇。虽然我不是OOP新手,但我还是刚接触Scala,并且还没有遇到过这样的情况。我发现即使只从traits继承(而不是一个类和多个traits),trait的“位置”也会对正确性产生影响,这让我感到很奇怪。 - user6454491
2个回答

4
  1. 这是不可能的。无论是通过特质还是其他方式,您都不能同时从两个不同的类继承。这很遗憾,但却是事实。我认为这没有非常好的理由,至少对于scala(而非“本机java”)类来说,实现起来会更加困难,但并非不可能。因此,显然在某个时候决定反对它,似乎没有一个好的理由。

  2. 扩展类的特质并不真正“异常”。更像是scala编译器处理它们的方式。基本上,任何属于或扩展类的内容都必须出现在extends子句中,而不是with中。为什么?为什么你不能使用==比较java中的Strings?因为...


2
@littlenag 从技术上讲,只要可以线性化,Scala 就不会禁止多重继承。您可以轻松地使用 traits 创建钻石形状,但它不会有 C++ 的问题(即 super 将被定义)。 - Victor Moroz
1
关于“super被定义”的问题,它并不像你想的那么简单。例如,请查看以下链接:https://dev59.com/RZXfa4cB1Zd3GeqPd11a - Dima
1
当然这并不是一件简单的事情,但它是确定性的:http://www.artima.com/pins1ed/traits.html#fig:linearization - Victor Moroz
1
@VictorMoroz 在任何(理智的)语言中都是确定性的,包括C++,SmallTalk等。 这里没有新闻。禁止从类中多重继承并没有任何优势。类和特征之间没有语义差异。区别只是一个特定于JVM实现的产物。我知道线性化如何工作,它对上述链接中描述的问题没有帮助(我认为这只是Scala编译器中的一个错误,而不是任何一种语言特性)。 - Dima
1
@Diego:是的,我在Smalltalk方面说错了话,我的错。关于trait组合和继承之间的语义差异,这是一个有趣的观点。你似乎在暗示super在类上下文中的含义与在trait上下文中的含义不同。你能否看一下这个问题,看看这个观察是否适用?https://dev59.com/RZXfa4cB1Zd3GeqPd11a - Dima
显示剩余8条评论

2
这是我的猜测:类可以带参数定义,现在让我们想象一下这种情况:
class A(val x: Int) 
class B extends A(1)
class C extends A(2)
trait D extends B
trait E extends C

// Oops! x = ? Doesn't compile of course
class F extends D with E

更新:

免责声明:我不是C ++专家

以下是C ++解决钻石问题的方法:

class A {
  int x;

public:
  A(int _x) {  x = _x; }
  int getX() { return x; };
};

class B : virtual public A {    
public:
  // B b; b.getX == 1
  B() : A(1) {}
};

class C : virtual public A {    
public:
  // C c; c.getX == 2
  C() : A(2) {}
};  

class D : public B, public C {
public:
  // I need to know that B/C inherit A
  // A(...) constructors defined above don't apply
  D(): B(), C(), A(3) {}
};

我想这正是Scala试图避免的问题。


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