Apple/Swift

[iOS/Swift] 구조체(Struct), 클래스(class) 란?

59date 2024. 7. 22. 00:41

구조체와 클래스의 공통점은

구조체와 클래스 모두 프로퍼티와 메서드를 포함하고 초기화할 수 있으며, 확장 기능성과 프로토콜 준수 등의 공통된 기능을 통해 데이터와 행동을 캡슐화할 수 있는 사용자 정의 데이터 타입입니다.

 

 

위 설명에서 사용자 정의 데이터 타입이란

배열로 먼저 예를 들면 배열은 동일한 데이터 타입을 하나의 묶음으로 나타내는 거지만 구조체와 클래스는 다른 데이터 타입들을 하나의 묶음으로 나타내는 것입니다 이것을 사용자 정의 데이터 타입이라고 합니다.

struct Person {
    var name: String
    var age: Int
}

이렇게 Person 구조체에 String타입의 name과 Int타입의 age와 같은 다른 타입을 하나의 묶음으로 나타낸 것을 알 수 있습니다.

 

 

다음은 차이점입니다.

구조체와 클래스의 차이점을 표로 비교해 보겠습니다.

구분 구조체 (Struct) 클래스 (Class)
타입 값 타입 (Value Type) 참조 타입 (Reference Type)
상속 지원하지 않음 지원함
초기화 자동 생성되는 이니셜라이저 제공 이니셜라이저를 명시적으로 정의해야 함
불변성 상수로 선언된 인스턴스는 불변 상수로 선언된 인스턴스도 변경 가능
메모리 스택 메모리에 저장 힙 메모리에 저장
복사 복사 시, 독립적인 인스턴스 생성 복사 시, 동일한 객체 참조
사용 예 간단한 데이터 모델링에 적합 복잡한 객체 구조와 행동 정의에 적합

구조체와 클래스의 차이점 중 가장 중요하게 봐야 할 세 가지 차이점은 타입, 상속, 초기화라고 생각합니다. 

 

 

다음 설명을 통하여 둘의 차이점을 자세하게 확인해 보겠습니다.

타입

  • 구조체 : 값 타입 (value type)으로, 인스턴스를 복사할 때 새로운 복사본이 생성됩니다. 즉, 하나의 구조체 인스턴스를 다른 변수나 상수에 할당하거나 함수의 인자로 전달할 때 실제 데이터의 복사본이 전달됩니다. 따라서 원본 데이터는 영향을 받지 않게 됩니다.
  • 클래스 : 참조 타입 (reference type)으로, 인스턴스를 복사할 때 원본 데이터에 대한 참조가 전달됩니다. 즉, 하나의 클래스 인스턴스를 다른 변수나 상수에 할당하거나 함수의 인자로 전달할 때, 동일한 인스턴스를 참조하는 것입니다. 따라서 원본 데이터가 변경되면 참조하는 모든 변수에 영향을 미치게 됩니다.

구조체

struct Person {
    var name: String
    var age: Int
}

var person1 = Person(name: "John", age: 25)
var person2 = person1  // person1의 복사본이 생성됩니다.

person2.name = "Jane"
print(person1.name)  // "John"
print(person2.name)  // "Jane"

위 코드에서 person1을 person2에 할당하면 person1의 복사본이 생성됩니다. 따라서 person2의 이름을 변경해도 person1의 이름은 영향을 받지 않습니다.

 

클래스

class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

var person1 = Person(name: "John", age: 25)
var person2 = person1  // person1에 대한 참조가 전달됩니다.

person2.name = "Jane"
print(person1.name)  // "Jane"
print(person2.name)  // "Jane"

위 예시에서 person1을 person2에 할당하면 person1과 person2는 동일한 인스턴스를 참조하게 됩니다. 따라서 person2의 이름을 변경하면 person1의 이름도 변경됩니다.

 

상속

  • 구조체 : 상속을 지원하지 않습니다. 즉, 구조체는 다른 구조체로부터 상속을 받을 수 없습니다.
  • 클래스 : 상속을 지원합니다. 기존 클래스를 기반으로 새로운 클래스를 정의할 수 있습니다.

구조체

struct Animal {
    var name: String
}

// 상속 시도 (컴파일 오류)
struct Dog: Animal {  
    var breed: String
}

위 예제처럼 구조체를 상속할 시 Inheritance from non-protocol type 'Animal'이라는 컴파일 오류를 발생시킵니다. 

해석해 보면 "Ingeritance" : 상속 / "from" : ~로부터 / "non-protocol type 'Animal'" : 프로토콜이 아닌 타입 'Animal'

따라서 전체 문구는 "프로토콜이 아닌 타입 'Animal'로부터의 상속"을 의미합니다.

 

클래스

class Animal {
    var name: String

    init(name: String) {
        self.name = name
    }

    func makeSound() {
        print("Some sound")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("Woof!")
    }
}

let animal = Animal(name: "Animal")
animal.makeSound()  // "Some sound"

let dog = Dog(name: "Dog")
dog.makeSound()  // "Woof!"

위 예시에서는 Animal 클래스와 Dog 클래스를 정의하고 있습니다. Dog클래스는 Animal 클래스를 기반으로 하며, Animal 클래스에서 제공하는 makeSound 메서드를 자신의 방식으로 재정의(오버라이드)합니다. 이 과정은 Dog 클래스가 Animal 클래스의 기능을 바탕으로 자신만의 기능을 추가하는 것과 같습니다.

 

초기화

  • 구조체
    • 초기값 설정 
      • 모든 저장 프로퍼티 초기화 : 구조체의 모든 저장 프로퍼티는 인스턴스를 생성하기 전에 반드시 초기화되어야 합니다. 구조체를 정의할 때, 프로퍼티에 기본값을 제공하거나 초기화 메서드를 통해 프로퍼티를 설정해야 합니다.
      • 기본값을 제공 : 프로퍼티에 가본값을 제공하며, Swift는 자동으로 초기화 메서드를 생성합니다. 기본값이 없는 경우, 모든 프로퍼티를 초기화하는 사용자 정의 초기화 메서드를 작성해야 합니다.
    • 자동 생성 초기화 메서드
      • 기본값이 있는 경우 : 기본값을 가진 프로퍼티가 있을 경우, Swift는 자동으로 모든 프로퍼티를 매개변수로 가지는 멤버와이즈 초기화 메서드를 생성합니다.
      • 기본값이 없는 경우 : 기본값이 없는 프로퍼티가 있을 경우, 자동 생성되는 초기화 메서드가 없기 때문에, 모든 프로퍼티를 초기화하는 사용자 정의 초기화 메서드를 작성해야 합니다.
  • 클래스 
    • 초기화 메서드 정의
      • 사용자 정의 초기화 메서드 : 클래스는 사용자 정의 초기화 메서드를 정의할 수 있습니다. 모든 저장 프로퍼티에 기본값을 설정할 필요는 없지만 초기화 메서드에서 모든 저장 프로퍼티를 초기화해야 합니다.
      • 초기화 메서드에서 모든 저장 프로퍼티 초기화 : 사용자 정의 초기화 메서드에서 모든 저장 프로퍼티에 값을 설정하여 인스턴스를 완전하게 초기화해야 합니다.
    • 초기값 설정
      • 저장 프로퍼티에 기본값 제공 : 저장 프로퍼티에 기본값을 제공하지 않더라도, 사용자 정의 초기화 메서드를 통해 프로퍼티를 초기화할 수 있습니다.
      • 여러 형태의 초기화 : 기본 초기화 메서드와 사용자 정의 메서드를 모두 활용하여 다양한 형태로 클래스를 초기화할 수 있습니다.

구조체

// 기본값이 있는 저장 프로퍼티를 가진 구조체
struct Person {
    var name: String = "Unknown"  // 기본값 제공
    var age: Int = 0              // 기본값 제공
}

// 자동 생성된 초기화 메서드 사용
let person = Person()  // 기본값으로 초기화
print(person.name)  // "Unknown"
print(person.age)   // 0

// 기본값이 없는 저장 프로퍼티를 가진 구조체
struct Employee {
    var name: String
    var position: String
    
    // 사용자 정의 초기화 메서드
    init(name: String, position: String) {
        self.name = name
        self.position = position
    }
}

// 사용자 정의 초기화 메서드를 사용하여 인스턴스 생성
let employee = Employee(name: "Alice", position: "Manager")
print(employee.name)      // "Alice"
print(employee.position)  // "Manager"

 

 

기본값이 있는 구조체 : Person 구조체는 저장 프로퍼티에 기본값을 제공하여 자동으로 생성된 초기화 메서드를 사용합니다. 이로 인해 인스턴스를 생성할 때 기본값으로 초기화합니다.

기본값이 없는 구조체 : Employee 구조체는 저장 프로퍼티에 기본값이 없으며, 사용자 정의 초기화 메서드를 통해 모든 프로퍼티를 초기화합니다. 이로 인해 인스턴스를 생성할 때, 초기화 메서드를 통해 값을 설정해야 합니다. 

 

클래스

// 사용자 정의 초기화 메서드를 가진 클래스
class Person {
    var name: String
    var age: Int
    
    // 사용자 정의 초기화 메서드
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

// 모든 프로퍼티를 초기화하는 사용자 정의 초기화 메서드 사용
let person = Person(name: "Bob", age: 25)
print(person.name)  // "Bob"
print(person.age)   // 25

// 저장 프로퍼티에 기본값을 제공하지 않는 클래스
class Employee {
    var name: String = "Unknown"  // 기본값 제공
    var position: String
    
    // 사용자 정의 초기화 메서드
    init(position: String) {
        self.position = position
    }
}

// 기본값을 제공하는 프로퍼티와 사용자 정의 초기화 메서드를 사용하여 인스턴스 생성
let employee = Employee(position: "Engineer")
print(employee.name)      // "Unknown"
print(employee.position)  // "Engineer"

사용자 정의 초기화 메서드 : Person 클래스는 모든 저장 프로퍼티를 초기화하는 사용자 정의 초기화 메서드를 제공합니다. 이를 통해 인스턴스 생성 시 프로퍼티를 설정할 수 있습니다.

기본값과 사용자 정의 초기화 : Employee 클래스는 프로퍼티 name에 기본값을 제공하면서, 다른 프로퍼티 position을 사용자 정의 초기화 메서드로 설정합니다. 기본값이 있는 프로퍼티는 초기화 메서드가 없더라도 기본값으로 초기화되고, 기본값이 없는 프로퍼티는 초기화 메서드를 통해 설정됩니다. 

 


 

잘못된 내용 혹은 오타가 있거나 더 좋은 내용 피드백은 언제나 환영입니다 :)