클래스는 초기화가 필요한 반면 구조체는 초기화가 필요하지 않다.
class Person { // error: Class 'Person' has no initializers
var name: String
var age: Int
}
struct Person {
var name: String
var age: Int
}
인스턴스의 프로퍼티에 값이 있다는 것이 항상 보장되어야 한다. 위의 클래스는 정의된 프로퍼티에 기본값이 없기 때문에 프로퍼티를 채워주는 초기화 메서드를 만들어주어야 한다. 디이니셜라이저 또한 클래스에서만 제공되는 메서드이다.
구조체는 초기화 하지 않아도 에러가 발생하지 않는다. 그 이유는 구조체는 memberwise라는 기능을 제공하기 때문이다. (메모리 위에서 관리되는 방식이 구조체와 클래스가 다르다)
memberwise?
구조체에서 제공하는 기능으로..
클래스에서만 가능하다. 한 클래스가 다른 클래스에 프로퍼티와 메서드를 물려주는 것을 말한다. 기존 클래스의 특성을 재사용하여 중복을 피하고 유지보수성을 높일 수 있고, 부모 클래스와 자식 클래스 간에 계층 구조를 형성하여 다양한 수준의 추상화와 분류가 가능해 진다.
class Person {
var age: Int = 0
func isBirthday(){
print("happy birthday")
age += 1
}
}
class Woman: Person{
var child = 0
func pregnant() {
child += 1
}
}
위의 코드에서 Woman은 Person 타입을 상속받았다. Person은 부모클래스가 되고, Woman은 자식클래스가 된다.
override는 재정의 구문이다. 재정의를 통해 자식클래스가 부모클래스의 기능을 변경해 사용할 수 있다.
class Person {
var age: Int = 0
func isBirthday(){
print("happy birthday")
age += 1
}
}
class Woman: Person{
var child = 0
override func isBirthday() {
age += 2
}
}
let amy: Woman = Woman()
amy.isBirthday()
print(amy.age) //2
super 키워드는 자식 클래스에서 부모 클래스의 메서드, 속성 또는 초기화 메서드를 호출할 때 사용된다.
class Person {
var age: Int = 0
func isBirthday(){
print("happy birthday")
age += 1
}
}
class Woman: Person{
var child = 0
override func isBirthday() {
super.isBirthday()
age += 2
}
}
let amy: Woman = Woman()
amy.isBirthday()
print(amy.age) //happy birthday
//3
final 키워드는 클래스, 메서드, 속성 등에 사용되며 클래스에 사용될 경우 클래스를 상속받을 수 없고 메서드나 속성 등에 사용되면 해당 멤버들을 재정의할 수 없다.
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func addAge() {
self.age += 1
}
}
struct Person {
var name: String
var age: Int
mutating func addOneToAge() {
self.age += 1
}
}
구조체는 값 타입이기 때문에 메서드 내에서 해당 구조체의 속성을 변경하는 것이 기본적으로 허용되지 않는다. 구조체에서 자신의 프로퍼티 값을 변경하려면 메서드 앞에 mutating이라는 키워드를 붙여주어야 한다.
구조체는 값타입으로 인스턴스에 값을 전달할 때 값을 복사하여 전달한다. 반면 클래스는 참조타입으로 참조하여 전달한다.
구조체는 값을 복사해서 전달한다면 클래스는 값의 주소를 전달한다고 생각하면 된다! (열거형도 값 타입이다)