Наследование

Последнее обновление: 02.01.2018

Одним из ключевых механизмов объектно-ориентированного программирования является наследование. В Swift классы могут наследовать функционал от других классов.

Класс-наследник еще называют подклассом, а класс, от которого наследуется функционал, - базовым классом или суперклассом.

Классы в Swift имеют полноценный доступ ко всем методам, свойствам, которые определены в суперклассе. Однако при необходимости подклассы могут переопределять наследуемый функционал суперклассом, например, изменять поведение методов или свойств.

Общий синтаксис наследования классов выглядит следующим образом:

class SubClass: SuperClass{
}

Для примера наследования рассмотрим простейшую ситуацию. Пусть у нас есть класс человека и класс служащего:

class User{

	var name: String
	var surname: String
	
	init(name: String, surname: String){
		
		self.name = name
		self.surname = surname
	}
	
	func getFullInfo() -> String{
		
		return "\(self.name) \(self.surname)"
	}
}

class Employee : User{
	
	var company: String
	init(name: String, surname: String, company: String){
		
		self.company = company
		super.init(name: name, surname: surname)
	}
}

Здесь класс Emplyee наследуется от класса User. Ведь класс сотрудника по сути будет повторять функционал класса человека, так как каждый сотрудник имеет имя и фамилию. И наследование в данном случае помогает избежать ненужного повторения при определении свойств и методов.

А после создания объекта Employee мы можем через него обращаться к свойствам и методам базового класса User:

var emp: Employee = Employee(name: "Steve", surname: "Jobs", company:"Apple")
var emplInfo = emp.getFullInfo()	// Steve Jobs
emp.name = "Tim"
emp.surname = "Cook"

Ключевое слово super

Ключевое слово super позволяет обращаться из подкласса к свойствам и методам базового класса. В выше приведенном примере ключевое слово super используется для обращения к инициализатору базового класса ля передачи ему значений.

Переопределение методов

Подкласс может перенимать полностью функционал базового класса, а может и переопределять его. Для переопределения используется ключевое слово override.

class User{

	var name: String
	var surname: String
	
	init(name: String, surname: String){
		
		self.name = name
		self.surname = surname
	}
	
	func getFullInfo() -> String{
		
		return "\(self.name) \(self.surname)"
	}
}

class Employee : User{
	
	var company: String
	init(name: String, surname: String, company: String){
		
		self.company = company
		super.init(name: name, surname: surname)
	}
	
	override func getFullInfo() -> String{
		
		return "\(self.name) \(self.surname) - \(self.company)"
	}
}

var emp: Employee = Employee(name: "Steve", surname: "Jobs", company:"Apple")
print(emp.getFullInfo())   // Steve Jobs - Apple

В данном случае мы переопределяем метод getFullInfo(). Теперь кроме имени и фамилии он также возвращает данные о компании, в которой сотрудник работает. И всегда, когда мы будем вызывать метод getFullInfo() у объекта Employee, будет срабатывать именно переопределенная версия метода.

Используя ключевое super, мы можем переопределить метод по-другому:

override func getFullInfo() -> String{
		
	return "\(super.getFullInfo) - \(self.company)"
}

или

override func getFullInfo() -> String{
		
	return super.getFullInfo() + " - \(self.company)"
}

Переопределение свойств

Подобным образом мы можем переопределять свойства:

class User{

	var name: String
	var surname: String
	
	init(name: String, surname: String){
		
		self.name = name
		self.surname = surname
	}
	
	var fullInfo: String{
		
		return "\(self.name) \(self.surname)"
	}
}

class Employee : User{
	
	var company: String
	init(name: String, surname: String, company: String){
		
		self.company = company
		super.init(name: name, surname: surname)
	}
	
	override var fullInfo: String{
		
		return super.fullInfo + " - \(self.company)"
	}
}

var emp: Employee = Employee(name: "Steve", surname: "Jobs", company:"Apple")
print(emp.fullInfo)   // Steve Jobs - Apple

В данном случае переопределяется свойство fullInfo.

Переопределение инициализаторов

При переопределении инициализатора необходимо вызвать инициализатор базового класса для инициализации тех свойств, которые определены в базовом классе. Кроме того, если в подклассе есть собственные свойства, их необходимо инициализировать до вызова инициализатора базового класса:

class User{

	var name: String
	var surname: String
	
	init(name: String, surname: String){
		
		self.name = name
		self.surname = surname
	}
	
	var fullInfo: String{
		
		return "\(self.name) \(self.surname)"
	}
}

class Employee : User{
	
	var company: String
	override init(name: String, surname: String){
		
		self.company = "Unknown"
		super.init(name: "Mr." + name, surname: surname)
	}
	
	init(name: String, surname: String, company: String){
		
		self.company = company
		super.init(name: name, surname: surname)
	}
	
	override var fullInfo: String{
		
		return super.fullInfo + " - \(self.company)"
	}
}

var emp: Employee = Employee(name: "Tim", surname: "Cook")
print(emp.fullInfo)   // Mr. Tim Cook - Unknown

Обязательные инициализаторы

В предыдущем примере нам было необязательно переопределять инициализатор класса User в классе Employee. Однако с помощью ключевого слова required мы можем отметить этот инициализатор как обязательный для переопределения в подклассах:

class User{

	var name: String
	var surname: String
	
	required init(name: String, surname: String){
		
		self.name = name
		self.surname = surname
	}
}

class Employee : User{
	
	var company: String
	required init(name: String, surname: String){
		
		self.company = "Unknown"
		super.init(name: "Mr." + name, surname: surname)
	}
	
	init(name: String, surname: String, company: String){
		
		self.company = company
		super.init(name: name, surname: surname)
	}
}

Запрет переопределения

С помощью ключевого слова final мы можем запретить переопределение свойств, методов, сабскриптов в производном классе:

class User{

	var name: String
	var surname: String
	
	init(name: String, surname: String){
		
		self.name = name
		self.surname = surname
	}
	
	final var fullInfo: String{
		
		return "\(self.name) \(self.surname)"
	}
}

Теперь свойство fullInfo нельзя будет переопределить в производном классе.

Более того мы можем вообще запретить наследование класса, поставив перед его определением ключевое слово final:

final class User{
	
	//.............
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850