Я новичок в Swift, поэтому я мог бы делать что-то глупое. Если это так, отлично: пожалуйста, скажите мне, где!Быстрый вызов виртуального метода приводит к segfault
В следующем коде, вы увидите, что класс Derived
наследует от общего класса Base<T>
:
class Base<T> {
func method(Int) -> T {
fatalError("Subclasses must override method.")
}
}
class Derived<T> : Base<Int> {
override func method(input:Int) -> Int {
return input
}
}
В Swift 1.1, это не возможно для не-универсальный класс наследовать от общий. Следовательно, Derived
в этом случае имеет переменную типа фиктивного типа.
Если я теперь использовать эти классы:
class Container {
let item: Base<Int>
init(item:Base<Int>) {
self.item = item
}
func method(input:Int) -> Int {
return item.method(input)
}
}
let a = Derived<Int>()
let b = Container(item:a)
let test = b.method(42)
код компилируется нормально, но я получаю Segfault когда Derived<Int>.method
вызывается. Основываясь на моей отладке до сих пор, похоже, что указатель self
верен в пределах Container.method
, но неправильно, когда мы попадаем в Derived<Int>.method
. Возможно, происходит некоторая коррупция в стеке?
Различные незначительные изменения в этом коде заставляют его работать нормально (хотя и с другой семантикой). Может ли кто-нибудь объяснить, что здесь происходит? Я не решаюсь предложить ошибку компилятора, пока не узнаю немного о Свифте.
Спасибо за подробный ответ. Вы отмечаете, что «Требование сделать производные классы родовыми есть по какой-то причине». Вы знаете, что это за причина, кроме недостающей функции? – olliew
Я также ценю вашу рекомендацию по дизайну кода, который я разместил. К сожалению, мне нужно использовать вызовы виртуальных методов в реальном коде, который я создаю. Протокол с 'typealias' в нем не может рассматриваться как абстрактный класс и только как ограничение типа. Вот почему я переработал свой код, чтобы использовать наследование, и вот тут эта ошибка появилась. – olliew
Я отчасти догадываюсь, так как официальные документы не говорят, но мое объяснение того, почему производные классы дженериков должны быть общими, будет: общие классы могут различаться по размеру - то есть класс 'A {let t: T} 'будет другого размера в зависимости от того, был ли T« Int »(размером 8) или« String »(размер которого равен 24). Производный класс также может быть разным по размеру, потому что его база может и, следовательно, учитывать это, должна быть общей. –