Swift语言中的抽象函数

我想用迅捷的语言创build一个抽象函数。 可能吗?

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 } } 

你想要的不是一个基类,而是一个协议。

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

如果你没有在你的类中提供abstractFunction,那是错误的。

如果你仍然需要其他行为的基类,你可以这样做:

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

我从一个支持抽象基类到Swift的平台移植了大量的代码,并运行到这个很多。 如果你真正想要的是抽象基类的function,那就意味着这个类既可以作为基于共享的类function的实现(否则它只是一个接口/协议),它定义了必须实现的方法派生类。

要在Swift中做到这一点,你需要一个协议和一个基类。

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

请注意,基类实现共享方法,但不实现协议(因为它不实现所有的方法)。

然后在派生类中:

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

派生类从基类inheritancesharedFunction,帮助它满足协议的这一部分,协议仍然需要派生类来实现abstractFunction。

这种方法唯一的缺点是,由于基类没有实现协议,如果你有一个需要访问协议属性/方法的基类方法,你将不得不在派生类中覆盖它,并从那里调用基类(通过super)传递self以便基类有一个协议的实例来完成它的工作。

例如,可以说sharedFunction需要调用abstractFunction。 该协议将保持不变,现在类将如下所示:

 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满足协议的这一部分,但派生类仍然能够以合理直接的方式共享基类逻辑。

这似乎是苹果如何在UIKit中处理抽象方法的“官方”方式。 看一看UITableViewControllerUITableViewController的工作方式。 你做的第一件事就是添加一行: delegate = self 。 那么,这正是诀窍。

1.将抽象方法放入协议中

 protocol AbstractMethodsForClassX { func abstractMethod() -> String } 

2.写你的基类

 /// 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.编写子类。

 /// 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() 

查看Playground以查看输出。

一些备注

  • 首先,已经有很多答案。 我希望有人find这一个。
  • 问题实际上是要find一个模式来实现:
    • 一个类调用一个方法,该方法必须在其派生的子类之一中实现(重写)
    • 在最好的情况下,如果方法在子类中没有被覆盖,那么在编译期间得到一个错误
  • 关于抽象方法的事情是,它们是接口定义和基类中实际实现的一部分的混合体。 两者同时。 由于迅捷是非常新的和非常清晰的界定,它没有这样的快速,但“不洁”的概念(还)。
  • 对我来说(一个可怜的老Java家伙),这个问题不时演变。 我已经阅读了这篇文章中的所有答案,这一次我想我find了一个模式,看起来是可行的 – 至less对我来说。
  • 更新 :看起来苹果的UIKit实现者使用相同的模式。 UITableViewController实现UITableViewDelegate但仍需要注册为委托,通过明确设置delegate属性。
  • 这一切都在Xcode 7.3.1的Playground上进行testing

我明白你现在在做什么,我想你最好使用一个协议

 protocol BaseProtocol { func abstractFunction() } 

那么,你只要遵守协议:

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

如果你的类也是一个子类,那么协议遵循超类:

 class SubClass: SuperClass, ProtocolOne, ProtocolTwo {} 

这样做的一个方法是使用在基类中定义的可选闭包,孩子可以select是否实现它。

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

使用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 

不过, Steve Waddicor提到你可能需要一个protocol

那么,我知道我迟到了,我可能正在利用已经发生的变化。 对于那个很抱歉。

无论如何,我想提供我的答案,因为我喜欢做testing, fatalError()的解决scheme是AFAIK,不可testing,有例外的testing更难testing。

我会build议使用更快速的方法。 你的目标是定义一个具有一些共同细节的抽象,但是没有完全定义,即抽象方法。 使用一个定义抽象中所有预期方法的协议,既定义的方法,也定义那些不是。 然后创build一个协议扩展,实现在你的情况下定义的方法。 最后,任何派生类必须实现协议,这意味着所有的方法,但是协议扩展的一部分已经有了它们的实现。

用一个具体的函数扩展你的例子:

 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()得到的错误或者在运行时会发生的exception。

我不知道会不会有用,但是在尝试构buildSpritKit游戏时,我也遇到了与抽象方法类似的问题。 我想要的是一个抽象的动物类,它有诸如move(),run()等方法,但是精灵名字(和其他function)应该由类的子类提供。 所以我最终做了这样的事情(Swift 2testing):

 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"] } } } 

我理解这个问题,并正在寻找相同的解决scheme。 协议与抽象方法不一样。

在协议中,你需要指定你的类符合这样的协议,抽象方法意味着你必须重写这种方法。

换句话说,协议是可选的,你需要指定基类和协议,如果你不指定协议,那么你不必重写这样的方法。

抽象方法意味着你想要一个基类,但是需要实现你自己的方法,或者两个不相同的方法。

我需要同样的行为,这就是为什么我正在寻找一个解决scheme。 我猜Swift是缺less这样的function。

这个问题还有另外一个select,虽然与@ jaumard的build议相比还是有不足的地方。 它需要一个返回语句。 虽然我错过了要求它的观点,因为它直接抛出exception:

 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(); } } 

无论发生什么事情都是无法达到的,所以我不明白为什么要强制回报。