OOP와 클래스(Class)
- 프로그램이 복잡해지는 경우, 프로그램을 효율적으로 작성할 필요가 있으며, 이때 이용되는 개념들이 OOP와 Class라는 개념임
- Class는 객체 지향 프로그래밍(OOP, Object Oriented Programming)을 위해 사용되는 것으로, 데이터(속성)와 메서드(처리)를 함께 사용할 수 있는 구조로 이루어져 있음.
- 즉, 변수와 함수들을 하나의 객체(Object)로써 묶어서 관리할 수 있다는 의미!
1. OOP (객체지향 프로그래밍)
- OOP (Object Oriented Programming)란, 실체가 있는 모든 물체를 클래스와 인스턴스, 함수, 변수라는 object로 변화시켜서 프로그램을 구성하는 개발방식을 의미함
- 최소비용으로 최대효율을 얻기위해 개발되었고, 속성과 기능을 object라는 최소단위로 분리하는 프로그래밍의 패러다임을 의미함
- 하나의 패러다임일 뿐이기 때문에 기존의 프로그래밍 패러다임(Procedural Programming, Functional Programming)과의 우열을 가릴 수는 없지만, 속성과 기능이 증가할 때마다 배열과 함수를 계속 생성해야 하는 경우에 소스코드를 보다 효율적으로 관리할 수 있음
OOP 이전의 프로그래밍 패러다임과 OOP
- Procedural Programming (절차형, 순서형 프로그래밍)
- 조건, 기능, 변수를 순서대로 정의하고 실행하는 방법
- 간단한 프로그래밍에서 이용되는 일반적인 방법을 의미
- 조건 또는 기능이 증가할 때마다 함수와 변수등 정의해야할 요소들이 계속 증가하기 때문에 프로그램이 복잡해질수록 비효율적임
speed = 50
color = 'black'
model = 'CarModel'
print("Car Attribute: ", speed, color, model)
'''
Car Attribute: 50 black CarModel
'''
- Functional Programming (함수형 프로그래밍)
- 함수형은 함수의 사용을 극대화시켜서 코드의 가독성을 높여주는 형태
- 특정 상황에 특정 함수를 재사용하여 프로그래밍 효율을 높이기위해 고안된 방법
- 일반적으로 많이 쓰이고 있지만 이 역시도 프로그램이 복잡해지는 경우 비효율이 발생할 수 있어 절대적으로 좋은 프로그래밍 방식이라고는 볼 수 없음
def carAttribute():
speed = 50
color = 'black'
model = 'CarModel'
return speed,color,model
print("Car Attribute: ", carAttribute())
'''
Car Attribute: (50, 'black', 'CarModel')
'''
- Object Oriented Programming (객체지향 프로그래밍)
- 절차 프로그래밍과 다르게 기능별로 수행하며, 데이터(속성)와 메서드(처리)를 함께 사용할 수 있는 구조로 프로그래밍 하는 방법
- 주로 Class를 통해 구현되고, 클래스 선언 순서에 관계없이 실행할 수 있음
- Python의 자료형(int, float, bool, list, tuple ... 등)은 class의 형태로 구현된 것이며, 따라서 파이썬의 자료구조 및 자료형은 객체지향 프로그래밍이 적용된 것이라 볼 수 있음
- 다만, 무분별하게 활용하면 유지보수가 어려워질 수도 있기때문에 설계방향 및 서비스기능에 따라 사용하는 것이 좋으며, 기능별로 개체가 효율적으로(재사용가능하도록) 분리되어야 하기 때문에 효율적인 설계가 매우 중요함
class Car:
def __init__(self, speed, color, model):
self.speed = speed
self.color = color
self.model = model
def drive(self):
self.speed = 50
myCar = Car(0, "green", "testCar")
print("--------Car Object Create Complete--------")
print("Car Speed: ", myCar.speed)
print("Car Color: ", myCar.color)
print("Car Model: ", myCar.model)
'''
--------Car Object Create Complete--------
Car Speed: 0
Car Color: green
Car Model: testCar
'''
print("Car Speed by drive: ", myCar.speed)
'''
Car Speed by drive: 0
'''
myCar.drive()
print("Car Speed by drive: ", myCar.speed)
'''
Car Speed by drive: 50
'''
2. Class (클래스)
- Class에서는 변수, 함수 등을 함께 기술해야 하며, 이를
클래스 정의라고 함
- Class명은 맘대로 지어도 상관은 없지만, 일반적으로 변수이름과 구분하기 위해
첫문자는 대문자로 설정하는 것이 일종의 암묵적인 약속임 (변수의 첫문자는 클래스와 구분 짓기 위해 소문자로 설정하는 것이 국룰..!)
class 클래스명(상속받는 경우의 상위클래스):
def 메서드명(self, 인수 목록):
self.변수 = ...
...
return ...
- 클래스 정의 예시
- 여기서
self의 의미에 대해선 인스턴스의 개념과 클래스 변수의 개념을 함께 알아야 설명이 가능해서 이에 관련해선 2-4 파트에서 다시 다룰 것이고, 일단은 변수와 메서드에 self를 붙여야 객체로써 관리할 수 있다는 정도로 이해하고 넘어가도록 하자
class Person:
def getName(self):
return self.name
def getAge(self):
return self.age
- 인스턴스(instance)를 작성
- 클래스로부터 생성되는 각각의 존재를 인스턴스(instance)라 부름
- 예를 들면, Person 클래스로부터 작성된 개개인의 사람들이 각각 인스턴스에 해당함을 의미함
- 인스턴스는
클래스명()을 통해 정의할 수 있고, 인스턴스를 나타내는 변수(인스턴스명)에 대입하여 변수를 정의할 수 있음
- 이때 클래스의 메소드나 속성을 이용하기 위해
.을 통해 접근할 수 있음
인스턴스명 = 클래스명()
person1 = Person()
인스턴스명.속성
person1.name
인스턴스명.메서드(인수목록)
person1.getName()
class Person:
def getName(self):
return self.name
def getAge(self):
return self.age
person_1 = Person()
person_1.name = "홍길동"
person_1.age = 24
name_1, age_1 = person_1.getName(), person_1.getAge()
print(f"{name_1}님은 {age_1}세 입니다.")
'''
홍길동님은 24세 입니다.
'''
person_2 = Person()
person_2.name = "임꺽정"
person_2.age = 33
name_2, age_2 = person_2.getName(), person_2.getAge()
print(f"{name_2}님은 {age_2}세 입니다.")
'''
임꺽정님은 33세 입니다.
'''
3. 클래스 생성자(constructor)
- 인스턴스를 작성할 때 초기 값을 주거나, 초기화처리를 하고자 하는 경우 등
인스턴스가 작성될 때 처음에 반드시 처리되도록 하는 메서드를 생성자(constructor)라 부름
- 생성자는
__init__이라는 이름을 가지는 메서드로써 정의하고, 양옆의 2개의 언더바_는 반드시 지켜줘야함
def __init__(self, 인수목록):
...
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def getName(self):
return self.name
def getAge(self):
return self.age
persons = [Person("홍길동", 24), Person("임꺽정", 33)]
for person in persons:
name = person.getName()
age = person.getAge()
print(f"{name}님은 {age}세 입니다.")
'''
홍길동님은 24세 입니다.
임꺽정님은 33세 입니다.
'''
4. 클래스 변수와 클래스 메서드
- 현재까지 살펴본 메서드와 변수들은
self구문을 통해 정의되었고, 이는 각각의 인스턴스에 관련되어있는 변수(속성) 혹은 함수(메서드)였음
- 즉,
self가 붙어있는 변수는 인스턴스마다 다르게 저장되는 변수이기 때문에 이러한 변수를 인스턴스 변수라 부름
- 또한,
self를 인수로 가지는 메서드는 인스턴스 자기자신을 의미하는 것으로써 이러한 메서드를 인스턴스 메서드라 부름
- 하지만 각각의 인스턴스가 아닌 클래스 전체(전체 인스턴스)에서 공유하여 값을 저장하거나 처리해야하는 경우가 있을 수 있고, 이러한 경우엔 속성이나 메서드는 클래스 전체에 관련되어 따로 정의하거나 처리해주어야함
- 예를 들어 클래스를 통해 몇개의 인스턴스가 생성되었는지를 기억하고자 하는 경우에는 클래스 전체에서 값을 공유하여 저장해야 하고, 이처럼 클래스 전체에 관련된 속성과 메서드를
클래스 변수, 클래스 메서드라 부름
클래스 변수와 인스턴스 변수
class Person:
count = 0
def getName(self):
return self.name
- 위 예시처럼 클래스 아래에서 정의되어 클래스에 하나의 값만 존재하는 변수 혹은 속성을
클래스변수 혹은 정적변수라 부름
self가 붙어있는 데이터 속성은 인스턴스마다 값이 존재하기 때문에, 이러한 속성은 클래스 변수와 구분하기 위해 인스턴스 변수라 부름
클래스 메서드와 인스턴스 메서드
- 클래스 전체에 관련된 메서드를
클래스 메서드라 부르며, 클래스 메서드는 클래스 내부에서 정의할 메서드 위에 데코레이터(@classmethod)를 통해 정의해 주어야 함
@classmethod
def getCount(변수명):
return 변수명.count
클래스명.getCount()
self를 인수로서 가지는 메서드는 클래스 메서드와 구분짓기 위해 인스턴스 메서드라 부르고, 이때 self는 인스턴스 자신(자기자신)을 의미함
def getName(self):
return self.name
name = Person('이름').getName()
- 예시를 통해 알아보는 클래스 변수, 클래스 메서드
class Person:
inst_count = 0
def __init__(self, name, age):
Person.inst_count += 1
self.name = name
self.age = age
def getName(self):
return self.name
def getAge(self):
return self.age
@classmethod
def getCount(c):
return c.inst_count
persons = [Person("홍길동", 24), Person("임꺽정", 33), Person("무야호", 40)]
for person in persons:
name = person.getName()
age = person.getAge()
print(f"{name}님은 {age}세 입니다.")
print(f"\n총 인원수는 {Person.getCount()}명 입니다.")
'''
홍길동님은 24세 입니다.
임꺽정님은 33세 입니다.
무야호님은 40세 입니다.
총 인원수는 3명 입니다.
'''
5. 클래스의 캡슐화(capsulization)
- 객체지향 프로그래밍(OOP)에서는 본래 사물의 데이터를 속성으로 인스턴스화하여 정보를 처리하는데, 이러한 객체지향에서는 데이터 속성을 마음대로 변경 할 수 없도록 처리를 해주어야하고, 이러한 처리를 통해 잘못된 값이 설정되지 않도록 처리할 수 있음
- 일반적인 객체 지향에 의한 프로그래밍 언어에서는 클래스의 외부로부터 object 속성에 접근할 수 없도록 하는 구조를 사용하여, 프로그램에서 발생 가능한 문제를 미연에 방지하게 됨
- 하지만, Python에서는 언어의 간단한 사용을 중요시하다보니 object에 대한 접근제어를 위한 접근제어자를 제공하지 않기 때문에, 객체의 변수, 메서드, 함수에 직접적으로 접근할 수 있음
- 이러한 한계를 극복하기위해 파이썬에서는 직접 접근을 허용하지 않도록 규칙을 만들어 두었는데, 접근 정도와 단계를 나타내는
Notation이라는 개념을 통해 접근 가능한 정도를 설정할 수 있음
- 파이썬의 Notation에는 다음과 순서로 코드 접근을 어렵게 설정할 수 있음
- (접근 어려움) Private -> Protected -> Public (접근 쉬움)
Public : 내부와 외부에서 쉽게 접근할수 있고 수정할 수도 있음
Protected : 언더바 1개 _를 이름 앞에 붙여 외부에서 쉽게 접근하지 못하도록 함
- 실제로는 접근이 되지만 개발자간의 암묵적인 약속으로 정한 것이라 보면 됨
Private : 언더바 2개__를 이름 앞에 붙여 외부에서의 접근을 수정을 강제로 금지시킴
- TMI : 사실 아무리 Private으로 설정하더라도
_클래스이름__메서드이름 혹은 _클래스이름__변수이름형태로 접근하면 강제적으로 접근 할 수 있어서 파이썬 코드상으로 접근을 강제적으로 막을 방법이 없긴 해서, Python에서는 접근을 어렵게 하기위한 최선의 방법이라 생각하면 될 듯함
- 이처럼 데이터를 안전하게 유지하고, 외부로부터 마음대로 접근할 수 없도록 하는 것을 객체지향에서는
캡슐화(capsulization)라고 부름
class Encap:
def __init__(self,value):
self.value = value
print('init:', self.value)
def _set(self):
print('set:', self.value)
def printTest(self):
print('printTest:', self.value)
def __printTest2(self):
print('printTest:', self.value)
e = Encap(10)
'''
init: 10
'''
e.__init__(20)
e._set()
e.printTest()
'''
init: 20
set: 20
printTest: 20
'''
e.__printTest2()
'''
AttributeError: 'Encap' object has no attribute '__printTest2'
'''
e.__init__(30)
e._set()
e.printTest()
'''
init: 30
set: 30
printTest: 30
'''
- 특히 프로그램이 길어지고 다양한 변수를 선언하는 경우 클래스의 속성이 충돌(변수의 중복)할 수 있는데, 이럴땐 속성명을 다르게 해줘도 되지만 파이썬에서 활용할 수 있는 '비공개 속성'을 활용하여 충돌을 방지할 수 있음
class parent_class:
def __init__(self):
self.value = 30
self._value = 40
self.__value = 50
def get(self):
return self.value
class sub_class(parent_class):
def __init__(self):
super().__init__()
self.__value = 20
s = sub_class()
print(s.value)
print(s._value)
'''
30
40
'''
print('----- 어떤 클래스에서 값을 받아오냐에 따라 값의 정보가 바뀜 -----')
print(s._parent_class__value)
print(s._sub_class__value)
print('parent_class value:', s.get(), ', sub_class value:', s.value)
'''
----- 어떤 클래스에서 값을 받아오냐에 따라 값의 정보가 바뀜 -----
50
20
parent_class value: 30 , sub_class value: 30
'''
6. 클래스의 상속, 포함, 오버라이딩
상속(inheritance)
- 이미 정의한 클래스를 바탕으로 새로운 클래스를 정의할 수 있는데, 이처럼 새로운 클래스를 확장하여 정의하는 것을 클래스를
확장(Extension)한다고 표현함
- 이러한 클래스 확장은 기존 클래스의 속성과 메서드를
상속받는 형태로 이루어지며, 이때는 기존의 클래스의 속성과 메서드를 다시 적을 필요가 없이 새로운 속성과 메서드를 추가하여 코드를 작성할 수 있음
- 이처럼 새롭게 확장한 클래스가 기존의 클래스의 속성과 메서드를 물려받는 것을
상속(inheritance)이라 부름
- 속성과 메서드를 물려주는 기존 클래스를
기저클래스(base class)혹은부모클래스라 부름
- 속성과 메서드를 상속받는 새로운 클래스를
파생클래스(derived class)혹은자식클래스라 부름
class 파생클래스명(기저클래스명):
...
def 추가메서드명(self, 인수목록):
self.추가속성 = 값
...
class Person:
def __init__(self, name):
self.name = name
class Student(Person):
def study(self):
print (self.name + " studies hard")
class Employee(Person):
def work(self):
print (self.name + " works hard")
s = Student("Dave")
e = Employee("David")
s.study()
e.work()
'''
Dave studies hard
David works hard
'''
포함(Composition)
- 속성과 메서드를 모두 받는 상속과 달리 클래스의 일부 변수와 기능만 가져오는 경우는
포함(Composition)이라 부르며, 이때는 기저클래스나 파생클래스로 구분을 할 수 없고, 새롭게 정의하는 클래스 내부에서 클래스를 호출함으로써 가져올 수 있음
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def printPerson(self, name, age):
print('Person_printPerson', name, age)
class Student:
def __init__(self, name, age, id):
self.person = Person(name,age)
Person.__init__(self, name, age)
self.id = id
def test(self, score):
if score > 80:
return (self.person.printPerson(self.name, self.age))
else:
print (self.name + " needs supplementary lessons")
s = Student("Dave", 20, 1)
print("s.age:", s.name)
print("s.age:", s.age)
print("s.id:", s.id)
'''
s.age: Dave
s.age: 20
s.id: 1
'''
s2 = Student("Jamie", 25, 2)
print("s2.age:", s2.name)
print("s2.age:", s2.age)
print("s2.id:", s2.id)
'''
s2.age: Jamie
s2.age: 25
s2.id: 2
'''
print('-- test score result --')
s.test(90)
s2.test(11)
'''
-- test score result --
Person_printPerson Dave 20
Jamie needs supplementary lessons
'''
오버라이딩(overriding)
- 부모클래스를 상속받는 파생클래스에서는 부모클래스와 동일한 이름의 메서드를 가지게 할 수 있는데, 이러한 경우엔 메서드간의 충돌이 발생하는 것이 아닌 파생클래스에서 새롭게 정의된 메서드가 부모클래스의 메서드를 대신하여 이용되며, 이러한 처리방식을
오버라이딩(overriding)이라 부름
- 즉, 인스턴스가 파생클래스에서 정의된 인스턴스인 경우, 동일한 이름의 메서드 중 파생클래스에서 정의된 메서드가 실행된다는 뜻
- 이러한 오버라이딩은 생성자인
__init__ 함수를 파생클래스에서 다시 정의하는 경우에도 적용되고, 그외에 부모클래스와 동일한 이름의 함수로 새롭게 정의하면 새롭게 정의된 함수가 실행됨을 의미함
class Person:
def __init__(self, name):
self.name = name
def getName(self):
return self.name
class Customer(Person):
def getName(self):
return "고객명 : " + self.name
person_1 = Person("홍길동")
print(person_1.getName())
'''
홍길동
'''
customer_1 = Customer("홍길동")
print(customer_1.getName())
'''
고객명 : 홍길동
'''
super()함수
- 부모클래스에서 정의한 함수와 변수를 파생클래스에서 정의한 것처럼 사용할 수 있는데, 이러한 경우 두가지 방법 중 하나를 사용해야함
부모클래스명(생성자인수).함수명()
super().함수명()
super() 함수는 부모클래스의 인스턴스를 얻는 함수로써 super().함수명()을 통해서 부모클래스에서 정의된 해당 함수명에 정의된 변수와 기능들을 그대로 가져와서 실행시켜줄 수 있음
- 간혹
super() 함수를 부모클래스의 함수명과 파생클래스의 함수명이 중복된 경우에 사용할 수 있는 메서드라 설명하는 자료들이 있지만, 이는 정확한 표현이 아니라 생각함
- 왜냐하면
super() 뒤에 붙는 함수로 파생클래스와 중복되지 않는 다른 함수를 불러와서 사용할 수도 있기 때문에 super() 메서드는 함수를 덮어쓰는 오버라이딩(overriding)의 개념 보다는 일부 기능을 가져오는 포함(Composition)의 개념에 더 가깝다 볼 수 있음
- 쉽게 생각해서
super() 함수는 부모클래스로부터 코드를 그대로 복사해와서 코드를 간결하게 해주는 역할이라 보면 됨
- 즉, super()는 메서드 단위에서의 상속이며, 이때 상속받는 메서드의 모든 매개변수(인자)를 그대로 가져와 사용하게 되는 것!
class Person:
def __init__(self, name):
self.name = name
def getName(self):
return self.name
def printName(self):
return print(f'고객명 : {self.name}')
class Customer(Person):
def __init__(self, name, age):
super().__init__(name)
self.age = age
def getName(self):
return "고객님의 이름 : " + self.name
def getAge(self):
name = super().getName()
return f"{name}님 나이 : {self.age}"
def printAge(self):
user_name = Person(self.name).getName()
super().printName()
return print(f'{user_name}님의 나이 : {self.age}')
person_1 = Person("홍길동")
print(person_1.getName())
person_1.printName()
'''
홍길동
고객명 : 홍길동
'''
customer_1 = Customer("임꺽정", 23)
print(customer_1.getName())
print(customer_1.getAge())
'''
고객님의 이름 : 임꺽정
임꺽정님 나이 : 23
'''
customer_1.printName()
'''
고객명 : 임꺽정
'''
customer_1.printAge()
'''
고객명 : 임꺽정
임꺽정님의 나이 : 23
'''
7. 클래스의 특수 메서드
- 이번엔 고수준의 클래스 기능으로써, 클래스를 정의할 때 이미 정해져 있는 이름의 메서드인 특수메서드들을 간략하게 정리해보겠음
- 생성자인
__init__ 처럼 양쪽에 2개씩의 언더바__ 로 정의된 메서드이며, 이를 통해 다양한 방식으로 출력을 조절하거나 연산을 진행할 수 있으며, 기본적인 사용법은 생성자인 __init__ 메서드처럼 사용하면 됨
출력 관련 특수 메서드
__str__(self) : 내장함수 str()에 대응함, 문자열을 반환
__format__() : 내장함수 format()에 대응함, 문자형의 서식을 지정하여 반환
__int__(self) : 내장함수 int()에 대응함, 정수를 반환
__float__(self) : 내장함수 float()에 대응함, 부동 소수점을 반환
__repr__(self) : 내장함수 repr()에 대응함, 식의 평가(eval())가 되는 문자열 반환
- 문자열로 객체를 다시 생성하는 함수로 쉽게 말해서 str()과의 큰 차이점은 repr()은 따옴표가 달려서 출력된다는 점
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
str_ = self.name + "님"
return str_
pr = Person('임꺽정')
print(pr.name)
print(str(pr))
print(pr.__str__())
'''
임꺽정
임꺽정님
임꺽정님
'''
연산차 처리 관련 특수 메서드
- self는 왼쪽 오퍼랜드, other는 오른쪽 오퍼랜드
__add__(self, other) : 연산자 +에 대응함, 덧셈연산
__sub__(self, other) : 연산자 -에 대응함, 뺄셈연산
__mul__(self, other) : 연산자 *에 대응함, 곱셈연산
__truediv__(self, other) : 연산자 /에 대응함, 나눗셈연산
__mod__(self, other) : 연산자 %에 대응함, 나머지연산
컬렉션 자료형 관련 특수 메서드
__len__(self) : len(인스턴스)에 대응함, 길이를 반환함
__getitem__(self, 인덱스 또는 키) : 인스턴스[인덱스 또는 키]에 대응함, 요소 얻기
__setitem__(self, 인덱스 또는 키, 값) : 인스턴스[인덱스 또는 키] = 값에 대응함, 요소를 대입(할당)함
__delitem__(self, 인덱스 또는 키) : del 인스턴스[인덱스 또는 키]에 대응함, 요소를 삭제함
__iter__(self) : iter(인스턴스)에 대응함, 이터레이터를 반환함
__reversed__(self) : reversed(인스턴스)에 대응함, 역순의 이터레이터를 반환함
요약 및 마무리
- 이 글에서는 객체지향프로그래밍의 개념과 클래스에대해서 다루어보았음
OOP
- 프로그래밍의 3가지 패러다임
- Procedural Programming (절차형, 순서형 프로그래밍)
- Functional Programming (함수형 프로그래밍)
- Object Oriented Programming (객체지향 프로그래밍)
- OOP : 기능별로 수행하며, 데이터(속성)와 메서드(처리)를 함께 사용할 수 있는 구조로 프로그래밍 하는 방법, 주로 Class를 통해 구현되고, 클래스 선언 순서에 관계없이 실행할 수 있음
Class
- Class (클래스) 정의하기
- 변수, 함수 등을 함께 기술할 수 있음
- Class명의 첫문자는 대문자로 설정하는 것이 국룰
- self의 의미는 인스턴스와 관련되어 있음을 의미함
- 인스턴스(instance) : 클래스로부터 생성되는 각각의 존재를 의미, 메소드나 속성을 이용하려면
.을 통해 접근
- 인스턴스 변수 :
self.변수
- 인스턴스 메서드 :
def 메서드(self):
- 생성자(
__init__) : 초기값 및 초기화 메서드, 인스턴스 생성시 실행됨
- 클래스 메서드는 데코레이터(
@classmethod)를 통해 정의
- 캡슐화(capsulization) : 데이터를 안전하게 유지하고, 외부로부터 마음대로 접근할 수 없도록 하는 것
- 상속(inheritance) : 새롭게 확장한 클래스가 기존의 클래스의 속성과 메서드를 물려받는 것
- 속성과 메서드를 물려주는 기존 클래스 :
기저클래스혹은부모클래스
- 속성과 메서드를 상속받는 새로운 클래스 :
파생클래스혹은자식클래스
- 포함(Composition) : 클래스의 일부 변수와 기능만 가져오는 것
- 오버라이딩(overriding) : 부모클래스와 동일한 이름의 메서드를 가지는 경우 새롭게 정의된 메서드가 부모클래스의 메서드를 대신하여 이용되는 것
- super() 함수 : 부모클래스로부터 메서드 단위로 상속을 받는 것, 이때 상속받는 메서드의 모든 매개변수(인자)를 그대로 가져와 사용함
- 오버라이딩(overriding)의 개념 보다 포함(Composition)의 개념에 더 가까움
마무리
- 다소 내용이 많아지고 복잡해졌지만, 클래스는 많이 써보고 익숙해지는 것이 가장 중요하다 생각함
- 이후에 추가적인 학습을 통해 보완하거나 추가할 내용이 생기면, 업데이트를 지속적으로 해나갈 예정임
- 화이팅!