프날 오토핫키 강좌  v2

⚠ 이 강좌는 오토핫키 v2를 다룹니다

지금 보시는 강좌는 과거 오랜 시간동안 알려진 오토핫키(v1.1)의 차세대 버전인 오토핫키 v2를 다루고 있습니다.
만약 구버전인 '오토핫키 v1.1'의 강좌를 찾으신다면 프날 오토핫키 강좌(https://pnal.kr)를 봐주시면 되지만, 새로 오토핫키를 배우신다면 v2 버전을 배우시는 것을 강력히 추천드립니다.

61. 객체와 인스턴스, 클래스


이제 객체 지향 프로그래밍을 이해하기 위해 꼭 알아야하는 세 가지 개념을 배우겠습니다. 바로 '객체', '인스턴스', '클래스'입니다. 이들은 객체 지향 프로그래밍을 구성하는 세 가지 기본 개념입니다.

지금까지 배운 프로그램 제작 방식

만약 우리가 자동차를 운전하는 게임을 구현한다고 합시다. 여러 대의 자동차가 구현되어 있는 이 게임은, 당연히 각각의 자동차를 나타내는 변수가 작성되어 있을 것입니다. 각각의 자동차의 정보를 변수에 담으려면 지금까지 배운 바로는 아래와 같이 작성해야합니다.

1car_1_kind := "세단"
2car_1_name := "쏘나타"
3car_1_wheel := 4
4car_1_color := "빨강"
5car_1_weight := 1450
6
7... (이하 생략)
모든 상황에 대해 위와 같이 변수로 지정합니다.

위 예시는 한 대의 자동차의 일부 정보만 담은 모습입니다. 각각의 변수는 논리적으로 연결되어있지 않습니다. 우리는 보이는 변수명으로만 이것이 "1번 차량"의 정보임을 파악해야 합니다. 게다가, 차량의 기능을 정의하기 위해 아래와 같은 함수를 만들어야 합니다.

  • car_accel(): 차량을 가속한다.
  • car_break(): 차량을 감속한다.
  • car_gear_up(): 차량의 기어를 1단 올린다.
  • car_gear_down(): 차량의 기어를 1단 낮춘다.
  • car_wiper(): 차량의 와이퍼를 작동한다.

휴! 겨우 차량의 기능을 함수로 구현했습니다. 이제 각각의 함수를 호출하여 차량을 조작할 수 있습니다. 그런데, 모든 차량에 대해 이렇게 구현하려 보니 큰 문제가 생겼습니다.

먼저 각각의 변수를 모든 차량에 대해 다시 적어야합니다. 그 자체로도 엄청난 노동력이 들어가는 일이지만, 모든 차량에 대한 각각의 특징을 가진 변수를 매번 유지보수하는 상상을 해보세요. 과장 조금 보태서 실제 차를 하나 만드는 것이 낫겠군요.

또, 각각의 자동차마다 어떤 함수는 그대로 갖다 쓸 수 있고, 어떤 함수는 수정해서 써야 작동합니다. 어떤 함수는 아예 동작할 수 없어서 정의할 필요가 없는 반면, 그 차량만을 위한 새 함수를 작성해야 하는 경우도 있습니다. 예를 들어서, 오토바이는 와이퍼를 동작시키는 함수가 필요 없습니다. 트럭은 속도 제한 장치를 의미하는 변수가 필요합니다. 자동 변속기가 달린 차량은 기어 조작과 관련된 함수를 자동으로 제어하는 또다른 함수를 작성해야합니다.

결국 나름대로 야심차게 진행하던 프로그램 개발은 수많은 변수와 함수의 지옥에 빠집니다. 어떻게든 함수 안에 기능을 몰아넣으려고 하니, 함수가 비대해집니다(제가 말씀드렸듯 함수는 한 가지만 해야합니다!). 그런데, 아래와 같은 개념을 도입하면 어떨까요?

관련있는 변수나 함수는 한 묶음으로 관리하자!

흩뿌려져 있는 변수와 함수를 관리하기 위해 그 변수와 함수를 묶은 상위 개념의 무언가를 도입해보겠습니다.

객체

객체는 '함수'와 '변수'를 갖고 있는 개념적이거나 실체적인 집합입니다. 예를 들어서, "자동차" 객체는 차종, 이름, 바퀴 개수, 색상, 무게를 나타내는 변수와 가속(), 감속(), 기어 올리기(), 기어 내리기()라는 함수를 갖고 있습니다.

자동차라고 적힌 네모 틀 안에 차종, 이름, 바퀴 개수, 색상, 무게, 감속 함수, 감속 함수, 기어 올리기 함수, 기어 내리기 함수가 있는 모습 사진 1. 자동차를 객체로 본 모습

대상을 별개의 변수나 함수가 아닌, '객체'라는 개념으로 묶어보면 장점이 많습니다. 일단 이 '자동차' 객체를 하나 만들어서 코드에 작성하면 성질이 같은 여러 자동차를 프로그램에 등장시킬 수 있습니다. 각 자동차에 있는 변수와 함수를 조정하면 그 자동차의 성질을 바꿀 수 있습니다. 각각의 변수와 함수를 각 차량 단위로 관리할 수 있는 셈이죠. 정말 효율적입니다.

자동차 객체가 가지고 있는 요소에서 화살표 세 개가 나와 빨간 자동차 하나, SUV 자동차 하나, 이름이 다른 자동차 하나를 각각 가리키는 그림 사진 2. 자동차 객체를 조정하여 여러 자동차를 만든 모습

특히, 이런 '객체'는 현실 세계의 사물과 대응됩니다. 우리가 보는 사물은 그 성질과 동작을 갖고 있습니다. 시계는 동그랗고 바늘이 세 개(혹은 두 개) 달려있는 '성질'과 1초에 초침이 하나씩 움직인다는 '동작'이 있습니다. 시계를 객체로 생각하면 성질은 변수, 시간의 흐름에 따른 바늘의 움직임은 함수로 구현할 수 있습니다. 이 변수와 함수를 프로그램 단위의 무언가로 보지 않고, 하나의 객체가 갖고 있는 특징으로 보는 것이죠.

이해가 어려우시면 아래 그림을 보겠습니다. 기존 방식과 다르게, 객체라는 개념을 통해 서로 연관된 변수와 함수는 하나의 그룹으로 관리할 수 있습니다.

car_1_xxx 로 쓴 변수와 car_xxx()쓴 함수로 관리하던 기존의 트리 이미지(좌), car라는 객체 안에 이들을 넣어서 관리하는 모습(우) 사진 3. 객체를 썼을 때 더욱 구조화된 자동차 프로그램

인스턴스

설계한 객체를 사용하려면 일단 프로그램에서 쓸 수 있는 변수에 대입을 해야하는데, 그렇게 변수에 대입되어서 나온 객체를 인스턴스라고 합니다. 다시 위의 사진을 가져와보면, 오른쪽에 있는 세 대의 자동차를 인스턴스라고 할 수 있습니다.

자동차 객체가 가지고 있는 요소에서 화살표 세 개가 나와 빨간 자동차 하나, SUV 자동차 하나, 이름이 다른 자동차 하나를 각각 가리키는 그림 사진 4. 개념적인 자동차 하나에서 실체적인 자동차 세 대를 만든 모습

우리는 각각의 인스턴스가 갖고 있는 값과 함수를 프로그래밍에 이용할 수 있습니다. 앞서 언급한 자동차 운전 게임에 네 대의 자동차가 필요하다면, 우리는 네 개의 인스턴스를 만들어서 각각의 인스턴스가 가지고 있는 값을 조정할 수 있습니다. 이로써 성질이 다른 여러 대의 자동차를 프로그램에 등장시킬 수 있습니다.

우리는 (일반적으로) 프로그램에서 인스턴스를 이용하는 것입니다. 인스턴스는 객체이지만, 객체가 인스턴스인 것은 아닙니다. 포함 관계를 명확히 기억해주세요.

클래스

그럼 우리가 원하는 요소를 담은 객체를 만드려면 어떻게 해야할까요? 바로 클래스를 이용합니다.

클래스는 객체의 설계도입니다. 객체 안에 있는 여러 함수와 변수를 클래스 안에 적어두면, 프로그램은 클래스를 설계도로 하여 인스턴스를 만들 수 있습니다. 우리가 자동차 객체를 만들기 위해선 자동차 안에 들어가야 하는 변수와 함수를 클래스에 적습니다. 그 후 이 클래스를 이용하여 새 객체를 만들 수 있고, 이렇게 만들어진 객체를 "인스턴스"라고 하는 것입니다.

즉, 인스턴스는 클래스가 실체화된 객체입니다. 설계도(클래스)대로 구현된, 우리가 쓸 수 있는 객체이죠.

Tip: 멤버, 필드, 메서드

객체의 요소를 일컫는 용어에 관한 이야기를 하겠습니다. 아래와 같은 용어가 있는데 사실 외우려 하지 않아도 자연스레 쓰게 되는 말입니다.

  • 멤버: 객체가 가지고 있는 각 성질(요소)이며, 객체 안의 변수와 함수를 통칭합니다.
    • 멤버 변수: 객체가 가지고 있는 변수를 의미합니다.
    • 멤버 함수: 객체가 가지고 있는 함수를 의미합니다.
  • 필드: '멤버 변수'와 같습니다. 약간 다르지만 '속성'이라고도 합니다.
  • 메서드: '멤버 함수'와 같습니다.

즉, 객체를 구성하는 각 요소를 멤버라고 하는데, 멤버 변수 = 필드 = 속성 이며, 멤버 함수 = 메서드 입니다. '필드'와 '속성'은 묘하게 다른데, 나중에 설명드릴테니 일단은 같다고 알고 계셔도 무방합니다.

객체 사용하기

객체에 대한 이론적인 부분은 한 번에 이해되지 않을 수 있습니다. 그러나 한 번 사용해보면 이론적인 부분은 당장 이해 안되더라도 코드를 작성하기엔 문제 없을 것입니다.

1car1 := Car()
2car2 := Car()
3car3 := Car()
Car 클래스로 세 개의 인스턴스를 만든 모습

위 코드는 Car 클래스를 이용하여 세 개의 인스턴스를 만듭니다. 각 인스턴스의 이름은 car1, car2, car3입니다. Car는 함수처럼 보이고, 마치 함수의 반환값을 각 변수에 담은 모양새지만, Car가 클래스인 경우 이는 새 인스턴스를 만드는 구문이 됩니다.

각 인스턴스는 필드와 메서드를 가지고 있을 테고, "멤버 접근 연산자"를 이용하여 각 인스턴스의 멤버에 접근할 수 있습니다. 멤버 접근 연산자는 마침표(.)를 사용합니다.

1car1.color := "WHITE"
2MsgBox(car1.color)
3
4car2.wiper()
car1의 필드를 바꾸고 출력한 다음, car2의 메서드를 호출한 모습

아쉽게도, 우리는 클래스를 직접 만들지 않았기 때문에 위와 같은 구문을 실행시켜볼 순 없습니다. 다음 강에서 이 구문을 실행시킬 수 있는 Car 클래스를 만들며 내용을 더욱 익혀보겠습니다.

Tip: 이론 부분을 지금 당장 이해되지 않아도 됩니다!

지금 배운 내용은 객체 지향 프로그래밍이라고 할 수도 없는 아주 기초적인 개념이지만, 확실히 이해되어야 하는 부분임은 맞습니다. 그러나 객체 개념을 처음 알게된 여러분은 지금 이해가 어려운 것이 일반적입니다.

따라서, 지금 당장 이론 부분이 이해되지 않더라도 일단 아래의 내용만 "그렇구나"하고 넘어가보세요. 코드로 짜보면 지금 설명한 이론에 관한 의문이 저절로 해소될 가능성이 큽니다.

여러분이 지금 꼭 이해해야하는 내용
  1. 관련있는 변수와 함수를 묶어서 관리할 수 있는데, 그 묶음을 '객체'라고 하겠습니다.
  2. 우리는 객체명.변수 또는 객체명.함수()의 형태로 이들을 이용할 수 있습니다.
질문하러 가기