C++

[C++] 다형성(polymorphism)

mintuchel 2023. 1. 4. 16:41

 

다형성은 상속(IS-A) 관계에서 나오는 개념이다.

"상속"이란 주제에 포함되는 개념임

이것도 java랑 똑같다.

 

AAA형 포인터 변수는 AAA 객체 또는 AAA 클래스를

직접 혹은 간접적으로 상속하는 모든 객체를 가르킬 수 있다

 

이게 끝이다.

 

쉽게 말하자면, 모든 객체들은 부모클래스 포인터로 참조할 수 있다는 뜻

 

그럼 이 개복잡할거 같은 개념을 굳이 왜 쓰는걸까

아래 코드 ㄱㄱ 

 


이건 축구선수 클래스이다

Class FootballPlayer 

class FootballPlayer
{
private:
    int num;
    int salary;
    char name[20];
public:
    FootballPlayer(const char* myname, int n, int s) : num(n), salary(s)
    {
        strcpy(name, myname);
    }

    void GetFPInfo() {
        cout << "#" << num << " " << name <<" $"<<salary <<endl;
    }
};

 


이건 공격수 클래스임

Class Striker

글구 얘는 위의 축구선수 클래스를 상속함

축구선수 > 공격수 니까 

class Striker : public FootballPlayer {
private:
    int pace;
    int shotpower;
public:
    Striker(const char* myname, int n, int s, int pace, int shotpower) : FootballPlayer(myname,n, s) {
        this->pace = pace;
        this->shotpower = shotpower;
    }

    void GetFPInfo() {
        cout << "[ST] PACE: " << pace << " SHOTPOWER: " << shotpower << endl;
    }
};

 


이건 미드필더 클래스

Class Midfielder

얘도 축구선수 클래스 상속

 

class Midfielder : public FootballPlayer {
private:
    int pass;
    int soccerIQ;
public:
    Midfielder(const char* myname, int n, int s, int pass, int soccerIQ) : FootballPlayer(myname,n, s) {
        this->pass = pass;
        this->soccerIQ = soccerIQ;
    }

    void GetFPInfo() {
        cout << "[MF] PASS: " << pass << " SOCCERIQ: " << soccerIQ << endl;
    }
};

 


이건 모든 축구선수들의 급여를 계산하는 SalaryHandler class

 

class SalaryHandler {
private:
    int cnt;
    FootballPlayer* arr[SIZE];
public:
    SalaryHandler() {
        cnt = 0;
    }

    void AddPlayer(FootballPlayer* fpp) {
        arr[cnt++] = fpp;
    }

    void ShowAllSalary() const {
        for (int i = 0; i < cnt; i++) {
            arr[i]->GetFPInfo();
        }
    }
};

 

이 클래스가 중요하다

여기서 다형성 개념이 나옴 ㅇㅇ

 

FootballPlayer* arr[SIZE];

 

 여기서 보면 FootballPlayer 타입의 포인터를 저장하고 있다. 

그리고 아래 main 함수에서는 이 타입의 포인터로 Striker와 Midfielder 객체를 참조하고 있다.

이게 가능한 이유가 다형성이다!

부모클래스 포인터로 자식클래스 객체를 참조할 수 있게끔 만든 기능

 

그럼 도대체 이걸 왜 쓰는걸까

 

만약 이 다형성이란 기능이 없다면 우린 Striker 객체들을 저장하는 배열과 Midfielder들을

저장하는 배열을 따로따로 만들어서 객체들을 구분하여 저장해야함

그럼 AddPlayer함수도 바꿔야하고 (if Striker if Midfielder 코드 추가해야함)

ShowAllSalary 함수도 바꿔야함 (두 배열을 모두 참조돌리며 출력해야함)

 

그리고 cnt 변수도 두개만들어야함 (striker cnt 변수 midfielder cnt 변수)

여기다 만약 Defender 클래스까지 추가된다?

그럼 Handler 클래스 고치다 하루 다가는 날리는거임 ㅇㅇ

즉 개귀찮아지는거임 ㅇㅇ

 

이러면 Defender 배열도 만들고 함수에 Defender 위한 코드 다 추가하고 하 바꿀게 너무 많아진다

 

따라서 이렇게 다형성을 이용해서 다양한 클래스 객체들을 한 묶음으로 묶어놓고

그들의 공통된 부모클래스로 다같이 참조할 수 있게 하는 것이다

 

만에하나 FootballPlayer를 직접 혹은 간접적으로 상속하는 클래스가 추가된다 하더라도

Handler 클래스를 변경할 필요가 없어지고 유지/보수가 쉬워짐

 


이건 main함수

 

int main()
{
    SalaryHandler handler;
    // 공격수 벤제마 추가
    handler.AddPlayer(new Striker("BENZEMA", 9, 26,102, 109));
    // 미드필더 모드리치 추가
    handler.AddPlayer(new Midfielder("MODRIC",10, 24, 98, 112));
    handler.ShowAllSalary();
    return 0;
}

 

하지만 여기서도 문제가 발생한다.

왜 ShowAllSalary하면 해당 객체의 getFPInfo가 아닌 FootballPlayer 클래스의 getFPInfo로 나오는걸까

이건 가상함수를 통해 알 수 있음 ㅇㅇ