Python

[파이썬]클래스class Ⅱ (상속, 다중상속, 메소드오버라이딩)

뉴라코 2024. 11. 9. 15:20

 

상속 (Inheritance): 유닛 사이에서 반복되는 부분이 있을 때
class unit:
    def __init__(self,name,hp):
        self.name=name
        self.hp=hp
        
class attackunit(unit): #unit에서 상속받아 attackunit 만들겠다.
    def __init__(self,name,hp,damage): 
        unit.__init__(self,name,hp) #유닛에서 이닛(self,name,hp)를 상속 받겠다. 
        self.damage=damage #추가된 데미지

1. class unit과 class attackunit에서 self.name=name, self.hp=hp 멤버변수가 똑같음.

그래서 class unit에 있는 것을 상속해 오겠다! 라는 뜻으로 class attackunit(unit): 정의

*이때, unit을 부모 class, attackunit을 자식 class라고 부름

2. def __init__(self, name,hp,damage) 하고 다음 줄에 unit의 __init__을 가져오겠다는 뜻으로

unit.__init__(self,name,hp)를 작성

3. 그 밑에 damage 변수의 경우 unit에 없는 정보이므로 추가로 작성해줌.

 

다중상속(Multiple Inheritance):여러개의 부모로부터 상속 받겠다

* def __init__(self, 요소,요소) : init은 무조건 self 가장 먼저 적혀야함.

#일반 유닛
class unit:
    def __init__(self,name,hp):
        self.name=name
        self.hp=hp

#공격 유닛
class attackunit(unit):
    def __init__(self,name,hp,damage): #self. 을 통해서 변수에 접근
        unit.__init__(self,name,hp)
        self.damage=damage

    def attack(self,location): #공격함수, 메소드 앞에서 무조건 self 적기
        print("{0}:{1}방향으로 적군을 공격 합니다.[공격력 {2}] "\
            .format(self.name,location,self.damage)) 
            #location은 전달받은 값쓴다. 그 외 self.name, self.damage는 유닛 안에 있는 걸 쓰겠다.
        
    def damaged(self,damage): #공격받은함수
        print("{0}:{1} 데미지를 입었습니다. ".format(self.name,damage))
        self.hp-=damage
        print("{0}:현재 체력은 {1}입니다".format(self.name,self.hp))
        if self.hp<=0:
            print("{0}:파괴되었습니다".format(self.name))  


#드랍쉽: 공중유닛, 수송기. 마린,파이어뱃,탱크 등 수송. 공격x
#날 수 있는 클래스
class flyable:
    def __init__(self,flying_speed):
        self.flying_speed= flying_speed
    def fly(self,name,location):
        print("{0}:{1} 방향으로 날아갑니다.[속도{2}]"\
              .format(name,location,self.flying_speed))

#공중 + 공격 유닛 클래스
class flyableattackunit(attackunit,flyable): #공격유닛과 날수있는유닛을 상속받아 초기화 시켜줄 뿐
    def __init__(self,name,hp,damage,flying_Speed):
        attackunit.__init__(self,name,hp,damage) #self 절대 까먹지 말기
        flyable.__init__(self,flying_Speed)
        
        

#발키리:공중공격유닛. 한번에 14발 미사일 발사
valkyrie=flyableattackunit("발키리",200,6,5)
valkyrie.fly(valkyrie.name,"3시") 
#fly함수는 속도 정보만 있으므로 valkyrie.name이라고 별도 이름 추가

1. 공중에서 날 수 있는 유닛 class flyable과 공격할 수 있는 유닛 class attackunit을 부모 클래스로 다중상속 받고 싶음.

-> 밑에서 두 번째 문단에 class flyableattackunit을 만들고 부모클래스 두개를 적음(attackunit,flyable)

Terminal>>
발키리:3시 방향으로 날아갑니다.[속도5]

 

[유닛 간 위계 관계]


메소드 오버라이딩( method overriding )

부모클래스에서 정의한 메소드 말고 자식 클래스에서 정의한 메소드를 쓰고 싶을 때

메소드를 새롭게 정의해서 사용할 수 있는데 이것을 오버라이딩이라고 한다. 

-지상유닛인 vulture와 공중유닛인 battlecruiser의 속도 구현 시 나타나는 문제점 : 각각 다른 함수를 써야함.

#일반 유닛
class unit:
    def __init__(self,name,hp,speed): #벌쳐랑 배틀크루저를 위해서 speed 추가
        self.name=name
        self.hp=hp
        self.speed=speed

    def move(self,location):   #지상 유닛인 벌쳐를 위해서 move 함수 입력
        print("[지상 유닛 이동]")
        print("{0}:{1} 방향으로 이동합니다. [속도{2}]"\
              .format(self.name,location,self.speed))    

#공격 유닛
class attackunit(unit):
    def __init__(self,name,hp,speed,damage): #self. 을 통해서 변수에 접근
        unit.__init__(self,name,hp,speed)
        self.damage=damage

    def attack(self,location): #공격함수, 메소드 앞에서 무조건 self 적기
        print("{0}:{1}방향으로 적군을 공격 합니다.[공격력 {2}] "\
            .format(self.name,location,self.damage)) 
            #location은 전달받은 값쓴다. 그 외 self.name, self.damage는 유닛 안에 있는 걸 쓰겠다.
        
    def damaged(self,damage): #공격받은함수
        print("{0}:{1} 데미지를 입었습니다. ".format(self.name,damage))
        self.hp-=damage
        print("{0}:현재 체력은 {1}입니다".format(self.name,self.hp))
        if self.hp<=0:
            print("{0}:파괴되었습니다".format(self.name))  

#드랍쉽: 공중유닛, 수송기. 마린,파이어뱃,탱크 등 수송. 공격x
#날 수 있는 클래스
class flyable:
    def __init__(self,flying_speed):
        self.flying_speed= flying_speed
    def fly(self,name,location):
        print("{0}:{1} 방향으로 날아갑니다.[속도{2}]"\
              .format(name,location,self.flying_speed))

#공중 공격 유닛 클래스
class flyableattackunit(attackunit,flyable): 
    def __init__(self,name,hp,damage,flying_Speed):
        attackunit.__init__(self,name,hp,0,damage) #지상 스피드는 0
        flyable.__init__(self,flying_Speed)
        
#벌쳐: 지상 유닛, 기동성이 좋음(빠른속도)
vulture=attackunit("벌쳐",80,10,20)

#배틀크루저:공중 유닛, 체력 공격력 굿
battlecruiser=flyableattackunit("배틀크루저",500,25,3)

vulture.move("11시")
battlecruiser.fly(battlecruiser.name,"9시")
# 벌쳐와 배틀크루저 각각 다른 함수를 쓰니까 귀찮음(벌처는 .move, 배틀크루저는 .fly).

- vulture는 지상유닛이므로 .move(self,location) 함수로

battlecruiser는 공중유닛이므로 .fly(self,name,location) 함수로..

Terminal>>
[지상 유닛 이동]
벌쳐:11시 방향으로 이동합니다. [속도10]
배틀크루저:9시 방향으로 날아갑니다.[속도3]

-> 너무 귀찮다. 어차피 둘 다 이동을 나타내는 함수니까 합쳐보자!

 

- 공중 유닛에도 move 함수를 넣는다면(내가 넣고 싶은 유닛 안에 move함수 새롭게 정의)

#일반 유닛
class unit:
    def __init__(self,name,hp,speed):
        self.name=name
        self.hp=hp
        self.speed=speed

    def move(self,location):
        print("[지상 유닛 이동]")
        print("{0}:{1} 방향으로 이동합니다. [속도{2}]"\
              .format(self.name,location,self.speed))    

#공격 유닛
class attackunit(unit):
    def __init__(self,name,hp,speed,damage): #self. 을 통해서 변수에 접근
        unit.__init__(self,name,hp,speed)
        self.damage=damage

    def attack(self,location): #공격함수, 메소드 앞에서 무조건 self 적기
        print("{0}:{1}방향으로 적군을 공격 합니다.[공격력 {2}] "\
            .format(self.name,location,self.damage)) 
            #location은 전달받은 값쓴다. 그 외 self.name, self.damage는 유닛 안에 있는 걸 쓰겠다.
        
    def damaged(self,damage): #공격받은함수
        print("{0}:{1} 데미지를 입었습니다. ".format(self.name,damage))
        self.hp-=damage
        print("{0}:현재 체력은 {1}입니다".format(self.name,self.hp))
        if self.hp<=0:
            print("{0}:파괴되었습니다".format(self.name))  

#드랍쉽: 공중유닛, 수송기. 마린,파이어뱃,탱크 등 수송. 공격x
#날 수 있는 클래스
class flyable:
    def __init__(self,flying_speed):
        self.flying_speed= flying_speed
    def fly(self,name,location):
        print("{0}:{1} 방향으로 날아갑니다.[속도{2}]"\
              .format(name,location,self.flying_speed))

#공중 공격 유닛 클래스
class flyableattackunit(attackunit,flyable): 
    def __init__(self,name,hp,damage,flying_Speed):
        attackunit.__init__(self,name,hp,0,damage) #지상 스피드는 0
        flyable.__init__(self,flying_Speed)

    def move(self,location): #이 부분 넣은거임
        print("[공중 유닛 이동]")
        self.fly(self.name,location)


#벌쳐: 지상 유닛, 기동성이 좋음(빠른속도)
vulture=attackunit("벌쳐",80,10,20)

#배틀크루저:공중 유닛, 체력 공격력 굿
battlecruiser=flyableattackunit("배틀크루저",500,25,3)

vulture.move("11시")
battlecruiser.move("9시") 
#공중유닛 move 함수에서 이름은 self.name으로 이미 설정되므로 battlecruiser.name 안넣어도 됨.

1. 밑에서 네 번째 문단 공중유닛 안에 새롭게 정의한(지상유닛과 다르게 출력되는)def move(self,location)을 정의한다. 

2. 마지막 줄에서 battlecruiser.move("9시") 로 구현해서 vulture와 같이 move 함수를 이용한다. 

Terminal>>
[지상 유닛 이동]
벌쳐:11시 방향으로 이동합니다. [속도10]
[공중 유닛 이동]
배틀크루저:9시 방향으로 날아갑니다.[속도3]