sub-typing polymorphism __ 다형성과 virtual 함수

😎·2022년 12월 26일
0

CPP

목록 보기
26/46

sub-typing polymorphism

타입에 따른 멤버 함수 호출

부모와 자식 사이의 다형성에 관해 알아보자. 부모와 자식에 같은 이름의 함수가 오버라이딩 된 상태에서, 어떤 타입으로 객체를 생성하는지에 따라 객체가 어떤 클래스의 멤버 함수를 호출하는지 알아보자.

여기서 말하는 타입과 객체는 다음을 말한다.

// Warrior 클래스형 포인터 타입으로 Warrior 객체 생성
Warrior *a = new Warrior();

// Character 클래스형 포인터 타입으로 Warrior 객체 생성 
Character *b = new Warrior();

Charcter 클래스와 Warrior 클래스는 부모와 자식 관계이며, 같은 이름의 멤버 함수가 있다.

class Character {
    public:
     void sayHello(std::string const &target);
};

class Warrior : public Character {
     public:
      void sayHello(std::string const &target);
};

그렇다면 ab 객체에서 sayHello 함수를 실행한다면, 타입 기반으로 실행이 될까, 생성한 객체 기반으로 실행이 될까?

void    Character::sayHello(std::string const &target) {
      std::cout << "Hello " << target << " !" << std::endl;
}

void    Warrior::sayHello(std::string const &target) {
      std::cout << "F*** off" << target << ", I don't like you !" << std::endl;
}

int main(void) {
    Warrior *a = new Warrior();
    Character *b = new Warrior();

    a->sayHello("students");
    b->sayHello("students");
}

결과를 보면, 타입 기반으로 함수가 호출되는 걸 볼 수 있다. aWarrior 타입이었기 때문에 F*** off 로 시작하는 문장이 출력됐고, bCharacter 타입이었기 때문에 Hello 로 시작하는 문장이 출력되는 것을 확인할 수 있다.

이렇게 되는 이유는 컴파일 시 코드를 정적 바인딩되기 때문이다. 그렇기 때문에 어떤 클래스 기반으로 객체를 생성하든 타입에 맞는 멤버 함수가 호출한다.


클래스에 따른 멤버 함수 호출 __ virtual 멤버 함수, 가상함수

그렇다면 어떻게 해야 타입이 아닌 클래스에 따라 함수를 호출할 수 있을까? 이때 virtual 을 사용한다.

class Character {
    public:
     virtual void sayHello(std::string const &target);
};

class Warrior : public Character {
     public:
      virtual void sayHello(std::string const &target);
};

virtual 라는 예약어를 사용하면 해당 멤버 함수를 재정의할 것을 기대하고 정의하는 함수가 된다. 이를 가상함수라고 하며 파생 클래스에서 새로운 내용으로 재정의할 수 있다. 또한 이전에는 정적 바인딩을 했다면 포인터가 가리키는 객체에 따라 멤버 함수를 선택하는 동적 바인딩을 하게 된다.


전체 코드

  • cat 클래스와 주석 부분은 컴파일 시 에러 상황을 보여주기 위한 부분이다. 신경쓰지 않아도 된다.
#include <string>
#include <iostream>

class Character {
    public:
     virtual void sayHello(std::string const &target);
};

class Warrior : public Character {
     public:
      virtual void sayHello(std::string const &target);
};

class Cat
{
    //[...]
};

void    Character::sayHello(std::string const &target) {
      std::cout << "Hello " << target << " !" << std::endl;
}

void    Warrior::sayHello(std::string const &target)
{
      std::cout << "F*** off" << target << ", I don't like you !" << std::endl;
}

int main(void) {
    // 워리어는 워리어 클래스를 생성하기 때문에 작동한다.
    Warrior *a = new Warrior();

    // 캐릭터는 워리어클래스의 부모이기 때문에 작동한다.
    Character *b = new Warrior();

    // 캐릭터는 워리어 클래스의 상속을 받지 않기 떄문에 작동안한다.
    // Warrior *c = new Character();

    // 캐릭터는 고양이 클래스의 상속을 받지 않기 때문에 작도 안한다.
    // Character *d = new Cat();

    a->sayHello("students");
    b->sayHello("students");
}

참고 자료

https://coding-factory.tistory.com/699

profile
jaekim

0개의 댓글