Проблема очень тонкая. Как правило, ваш класс AA , который расширяет A , должен быть смешан с чертами, которые также расширяют A .
Вы сделали:
class A {
def b { }
}
abstract class AA extends A {
override def b
}
trait B {
def b { println("B") }
}
Следовательно, когда вы смешиваете AA и B , метод b определяется дважды. Один раз A (не переопределяется, поскольку определение в B заменяет переопределение в AA ), а второе - B , компилятор может не выбрал один над другим, потому что нет никакой иерархии между двумя (одинаково названными, но не связанными) методами. Если хотите, подумайте об этом так: компилятор «смешивает» тела AA и B ; если он выберет метод из AA , он будет абстрактным, если он выберет метод из B (что должно произойти), так как это не переопределение, вы застряли с двумя методами б .
Чтобы решить эту проблему, вы должны убедиться, что оба метода override
одинаковы, и в этом случае компилятор поймет, что вы говорите о том же методе, и отдаст приоритет последней смешанной характеристике.
Теперь, чтобы переопределить метод b в B , этот класс также должен наследоваться от A . Таким образом, канонический способ сделать это будет:
class A {
def b { }
}
abstract class AA extends A {
override def b
}
trait B extends A{
def b { println("B") }
}
class C extends AA with B {}
Что компилируется просто отлично.
Теперь, когда вы делаете:
abstract class AA {
def b
}
trait B {
def b { println("B") }
}
class C extends AA with B {}
ясно, что оба метода одинаковы, поэтому компилятор знает, что он должен использовать метод из черты.
Другие решения включают в себя:
- Сделать B переопределить AA
- Сделать b в A аннотацией (но вы этого не хотели)
Опять же, проблема очень тонкая, но, надеюсь, я немного прояснил ситуацию. Чтобы лучше понять, прочитайте Набор стековых черт Scala .