Абстрактные функции в языке Swift

Я бы хотел создать абстрактную функцию на языке быстрой речи. Является ли это возможным?

class BaseClass { func abstractFunction() { // How do I force this function to be overridden? } } class SubClass : BaseClass { override func abstractFunction() { // Override } } 

В Swift нет понятия абстрактного (например, Objective-C), но вы можете это сделать:

 class BaseClass { func abstractFunction() { preconditionFailure("This method must be overridden") } } class SubClass : BaseClass { override func abstractFunction() { // Override } } 

Вы хотите не базовый class, а протокол.

 protocol MyProtocol { func abstractFunction() } class MyClass : MyProtocol { func abstractFunction() { } } 

Если вы не предоставляете abstractFunction в своем classе, это ошибка.

Если вам по-прежнему нужен базовый class для другого поведения, вы можете сделать это:

 class MyClass : BaseClass, MyProtocol { func abstractFunction() { } } 

Я переношу довольно много кода с платформы, которая поддерживает абстрактные базовые classы для Swift и много работает с этим. Если вам действительно нужна функциональность абстрактного базового classа, то это означает, что этот class служит как реализация функциональности classа с общим доступом (иначе это будет просто интерфейс / протокол) И он определяет методы, которые должны быть реализованы посредством производные classы.

Для этого в Swift вам понадобится протокол и базовый class.

 protocol Thing { func sharedFunction() func abstractFunction() } class BaseThing { func sharedFunction() { println("All classes share this implementation") } } 

Обратите внимание, что базовый class реализует общий метод (ы), но не реализует протокол (поскольку он не реализует все методы).

Тогда в производном classе:

 class DerivedThing : BaseThing, Thing { func abstractFunction() { println("Derived classes implement this"); } } 

Производный class наследует sharedFunction от базового classа, помогая ему удовлетворить эту часть протокола, и для протокола по-прежнему требуется, чтобы производный class реализовал abstractFunction.

Единственным реальным недостатком этого метода является то, что, поскольку базовый class не реализует протокол, если у вас есть метод базового classа, которому необходим доступ к свойству / методу протокола, вам придется переопределить это в производном classе, а оттуда вызвать базовый class (через супер), передающий self так что базовый class имеет экземпляр протокола, с помощью которого можно выполнить свою работу.

Например, допустим, что sharedFunction необходимо вызвать abstractFunction. Протокол останется прежним, и classы теперь будут выглядеть так:

 class BaseThing { func sharedFunction(thing: Thing) { println("All classes share this implementation") thing.abstractFunction() } } class DerivedThing : BaseThing, Thing { func sharedFunction() { super.sharedFunction(self) } func abstractFunction() { println("Derived classes implement this"); } } 

Теперь sharedFunction из производного classа удовлетворяет той части протокола, но производный class по-прежнему способен разделить логику базового classа достаточно простым способом.

Этот, кажется, «официальный» способ использования Apple в абстрактных методах в UIKit. Взгляните на UITableViewController и на то, как он работает с UITableViewDelegate . Одна из первых вещей, которую вы делаете, – добавить строку: delegate = self . Ну, это точно трюк.

1. Поместите абстрактный метод в протокол

 protocol AbstractMethodsForClassX { func abstractMethod() -> String } 

2. Напишите свой базовый class

 /// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does) /// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate` class BaseClassX { var delegate: AbstractMethodsForClassX! func doSomethingWithAbstractMethod() -> String { return delegate.abstractMethod() + " - And I believe it" } } 

3. Запишите подclass (ы).

 /// First and only additional thing you have to do, you must set the "delegate" property class ClassX: BaseClassX, AbstractMethodsForClassX { override init() { super.init() delegate = self } func abstractMethod() -> String {return "Yes, this works!"} } 

Вот, как вы используете все это

 let x = ClassX() x.doSomethingWithAbstractMethod() 

Обратитесь к игровой площадке, чтобы увидеть результат.

Некоторые примечания

  • Сначала было дано много ответов. Я надеюсь, что кто-то найдет все, вплоть до этого.
  • На самом деле вопрос заключался в том, чтобы найти шаблон, который реализует:
    • Класс вызывает метод, который должен быть реализован в одном из полученных подclassов (переопределенных)
    • В лучшем случае, если метод не переопределяется в подclassе, получите ошибку во время компиляции
  • Дело в абстрактных методах заключается в том, что они представляют собой смесь определения интерфейса и части фактической реализации в базовом classе. Оба в то же время. Поскольку скорость очень новая и очень чистая, она не имеет такой уверенности, но «нечистые» концепции (пока).
  • Для меня (плохой старый Java-парень) эта проблема время от времени развивается. Я прочитал все ответы в этом посте, и на этот раз я думаю, что нашел шаблон, который выглядит выполнимым – по крайней мере для меня.
  • Обновление . Похоже, что разработчики UIKit в Apple используют один и тот же шаблон. UITableViewController реализует UITableViewDelegate но все же должен быть зарегистрирован как делегат, явно устанавливая свойство delegate .
  • Все это протестировано на игровой площадке Xcode 7.3.1

Один из способов сделать это – использовать необязательное закрытие, определенное в базовом classе, и дети могут выбрать его реализовать или нет.

 class BaseClass { var abstractClosure?:(()->())? func someFunc() { if let abstractClosure=abstractClosure { abstractClosure() } } } class SubClass : BaseClass { init() { super.init() abstractClosure={ ..... } } } 

Я понимаю, что вы сейчас делаете, я думаю, вам будет лучше использовать протокол

 protocol BaseProtocol { func abstractFunction() } 

Затем вы просто соглашаетесь с протоколом:

 class SubClass : BaseProtocol { func abstractFunction() { // Override println("Override") } } 

Если ваш class также является подclassом, протоколы следуют за суперclassом:

 class SubClass: SuperClass, ProtocolOne, ProtocolTwo {} 

Использование ключевого слова assert для применения абстрактных методов:

 class Abstract { func doWork() { assert(false, "This method must be overriden by the subclass") } } class Concrete : Abstract { override func doWork() { println("Did some work!") } } let abstract = Abstract() let concrete = Concrete() abstract.doWork() // fails concrete.doWork() // OK 

Однако, как сказал Стив Ваддикор, вы, скорее всего, хотите использовать protocol .

Ну, я знаю, что я опаздываю на игру и что могу воспользоваться теми изменениями, которые произошли. Извини за это.

В любом случае, я хотел бы внести свой ответ, потому что мне нравится делать тестирование, а решения с fatalError() – это AFAIK, не проверяемые, а те, с исключениями, намного сложнее тестировать.

Я бы предложил использовать более осторожный подход. Ваша цель – определить абстракцию, которая имеет некоторые общие детали, но это не полностью определено, т. Е. Абстрактный метод (ы). Используйте протокол, который определяет все ожидаемые методы в абстракции, как те, которые определены, так и те, которые не являются. Затем создайте расширение протокола, которое реализует методы, определенные в вашем случае. Наконец, любой производный class должен реализовать протокол, что означает все методы, но те, которые являются частью расширения протокола, уже имеют свою реализацию.

Расширение вашего примера с помощью одной конкретной функции:

 protocol BaseAbstraction { func abstractFunction() { // How do I force this function to be overridden? } } extension BaseAbstraction { func definedFunction() { print("Hello") } class SubClass : BaseAbstraction { func abstractFunction() { // No need to "Override". Just implement. } } 

Обратите внимание, что, сделав это, компилятор снова станет вашим другом. Если метод не «переопределен», во время компиляции вы получите сообщение об ошибке, а не те, которые вы получите с fatalError() или исключениями, которые произойдут во время выполнения.

Есть еще одна альтернатива этой проблеме, хотя по сравнению с предложением @ jaumard все еще есть недостаток; для этого требуется оператор return. Хотя я скучаю по этому требованию, потому что он состоит в том, чтобы прямо бросать исключение:

 class AbstractMethodException : NSException { init() { super.init( name: "Called an abstract method", reason: "All abstract methods must be overriden by subclasses", userInfo: nil ); } } 

А потом:

 class BaseClass { func abstractFunction() { AbstractMethodException.raise(); } } 

Все, что приходит после этого, недостижимо, поэтому я не понимаю, зачем принуждать возrotation.

Я не знаю, будет ли это полезно, но у меня была аналогичная проблема с абстрактным методом при попытке создать игру SpritKit. То, что я хотел, является абстрактным classом Animal, который имеет такие методы, как move (), run () и т. Д., Но имена спрайтов (и другие функции) должны предоставляться детьми classа. Поэтому я закончил делать что-то вроде этого (тестировался на Swift 2):

 import SpriteKit // --- Functions that must be implemented by child of Animal public protocol InheritedAnimal { func walkSpriteNames() -> [String] func runSpriteNames() -> [String] } // --- Abstract animal public class Animal: SKNode { private let inheritedAnimal: InheritedAnimal public init(inheritedAnimal: InheritedAnimal) { self.inheritedAnimal = inheritedAnimal super.init() } public required init?(coder aDecoder: NSCoder) { fatalError("NSCoding not supported") } public func walk() { let sprites = inheritedAnimal.walkSpriteNames() // create animation with walking sprites... } public func run() { let sprites = inheritedAnimal.runSpriteNames() // create animation with running sprites } } // --- Sheep public class SheepAnimal: Animal { public required init?(coder aDecoder: NSCoder) { fatalError("NSCoding not supported") } public required init() { super.init(inheritedAnimal: InheritedAnimalImpl()) } private class InheritedAnimalImpl: InheritedAnimal { init() {} func walkSpriteNames() -> [String] { return ["sheep_step_01", "sheep_step_02", "sheep_step_03", "sheep_step_04"] } func runSpriteNames() -> [String] { return ["sheep_run_01", "sheep_run_02"] } } } 

Я понимаю вопрос и искал одно и то же решение. Протоколы – это не то же самое, что абстрактные методы.

В протоколе необходимо указать, что ваш class соответствует такому протоколу, абстрактный метод означает, что вы должны переопределить такой метод.

Другими словами, протоколы являются опциями, вам нужно указать базовый class и протокол, если вы не укажете протокол, тогда вам не нужно переопределять такие методы.

Абстрактный метод означает, что вы хотите базовый class, но вам нужно реализовать свой собственный метод или два, что не то же самое.

Мне нужно такое же поведение, поэтому я искал решение. Я думаю, что Swift отсутствует такая функция.

  • Почему я не могу наследовать статические classы?
  • Список всех базовых classов в иерархии данного classа?
  • Нельзя наследовать от std :: vector
  • когда тег «a» не наследует атрибут цвета родительского тега?
  • Является ли ключевое слово 'override' просто проверкой переопределенного виртуального метода?
  • Должно ли C # иметь множественное наследование?
  • Может ли controller AngularJS наследовать от другого controllerа в том же модуле?
  • можно ли вызвать переопределенный метод из родительской структуры в golang?
  • Наследуются ли виртуальные деструкторы?
  • Почему я должен объявлять виртуальный деструктор абстрактного classа на C ++?
  • Наследование и зависимость
  • Давайте будем гением компьютера.