Skip to content

Inheritance (상속)

OOP에서 애용되는 Object간의 관계(relation) 중의 하나이다. Inheritance를 통해 생성되는 관계가 is-a관계 (이후 다룸)임.

Hierarchy(계층화)와 함께 modularity (모듈화)와 코드의 재사용성을 극대화 시킬 수 있는 방법임.

Hierarchy(계층화) 를 다시 한번 읽어볼 것.


Class의 Hierarchy 구조

Class에서의 Hierarchy는 inheritance를 통해 이루어진다. 다음은 판타지 게임의 인간 종족을 abstraction하고 이들을 상속을 통해 계층화 한 Diagram이다.

inheritance를 통해

  • 기존 class와 구분되는 특징 만을 기술하여
  • subclass(하위 class) 로 추가.

상속에 따라 attribute(특성)을 공유하게 됨. ← 재사용성이 높아짐.

  • attributes는 Python의 용어로서 class가 가지고 있는 methods와 variables를 가르킴.

Python이나 Java는 모든 class에서 가져야할 attributes를 Object 라는 클래스에 구현하고 이를 상속받는 구조를 취함으로서 재사용성을 극대화하고 구현코드를 최소화함.

용어들은 다음과 같음.

  • parent class = super class = 상위클래스
  • child class = sub class = 하위클래스

Example (Python)

class Human:
    def __init__(self, name):
        Human.ds_type = "Human"
        self.job = None
        self.name = name

    def introduce(self):
        print("------------------------")
        print(f"제 이름은 {self.name}입니다.")
        print(f"제 직업은 {self.job}입니다.")
        print(f"저의 종족은 {Human.ds_type}입니다.")

class Warrior (Human):

    def __init__(self, name):
        super().__init__(name)
        self.job = "Warrior"

    def bash (self):
        print("강타 능력")

class Knight(Warrior):
    def __init__(self, name):
        super().__init__(name)
        self.job = "knight"
    def riding (self):
        print("말타기 능력")

class Healer (Human):
    def __init__(self, name):
        super().__init__(name)
        self.job = "Healer"

    def healing (self):
        print("치료하기 능력")

if __name__ == "__main__":
    ins0 = Human("김 아무개")
    ins1 = Warrior("이 아무개")
    ins2 = Healer("박 아무개")
    ins3 = Knight("박 기사")

    humans = [ins0, ins1, ins2, ins3]
    for h in humans:
        h.introduce()    
  • 생성자 __init__(self, name)를 모든 sub-class에서 over-riding하고 있음.
  • over-riding할 경우, super-class의 method는 가려져서 대체된다. 때문에 super-class의 것을 호출하기 위해선, super()를 통해 super-class의 object를 가져와서 호출해야함.
  • super().__init__(name)을 통해 super-class의 생성자를 호출하고 나서 sub-class 고유의 처리구문을 수행함.
  • over-riding을 하지 않는 경우, 기본적으로 super-class의 method를 사용한다. 위의 Humanintroduce메서드가 그 예임.
    • 즉, 공통적으로 사용되는 attributes들은 super class에 구현하는게 좋다.

over-riding과 over-loading은 다른 개념임. 그 차이점을 숙지하고 있어야 한다. 자세한 건 다음 url을 참고하라.
overriding and overloading

Multiple Inheritance (다중 상속)

두 개 이상의 super class가 필요한 경우 사용된다. Java와 같이 super class는 하나만을 허용하고, interface등을 통해 Multiple Inheritance의 기능을 구현하는 경우도 있다. 실제로 Multiple Inheritance는 편리하지만, 그만큼 충돌이 발생할 위험이 크다 는 부작용도 있다 (같은 이름의 method가 여러 super class에 존재시 어느 super class의 메서드를 우선시할지 등등).

  • multiple inheritance가 발생하면 다이아몬드 모양이 만들어진다고 해서 다이아몬드 상속이라고 부르기도 한다.

Python에서는 다중상속을 지원하고 Method Resolution Order (mro()로 확인 가능)에 따라, 왼쪽에 놓인 super class에서부터 우선권이 주어진다.

Example (Python)

...

class Paladin (Knight, Healer):
    def __init__(self, name):
        super().__init__(name)
        self.job = "Paladin"

if __name__ == "__main__":
    ...
    ins4 = Paladin("정 아무개")
    ins4.introduce()
    ins4.healing()
    ins4.riding()

    print(Paladin.mro())

맨 아래의 Paladin.mro()를 통해 상속관계(또는 우선권)을 확인할 수 있다. 해당 결과는 다음과 같다.

[<class '__main__.Paladin'>, <class '__main__.Knight'>,
 <class '__main__.Warrior'>, <class '__main__.Healer'>,
 <class '__main__.Human'>, <class 'object'>]
  • 여기서도 모든 Python의 object들은 Object라는 공통 super class를 가진다는 사실을 확인할 수 있다.
  • 오른쪽으로 갈수록 super class에 존재 (조상님이라는 애기임).