본문 바로가기

Google AdSense

C, C++

다형성(Polymorphism)

by 박__주홍 2020. 8. 25.

다형성은 오버로딩, 오버라이딩, 부모클래스를 가르키는 포인터변수가 자식클래스를 동적할당받은 주소를 받아 쓸 수 있는 그런 유연함을 얘기한다. 

 

1. 오버로딩은 클래스안 이름이 같은 함수, 같은 매개변수 수가 있더라도 그 매개변수 자료형이 다르면 같은 이름으로도 함수가 존재할 수 있다. 

 

2. 오버라이딩은 부모클래스의 함수 앞에 virtual을 쓰게 되면 자식클래스에서 그 함수에 무엇을 덧대어 사용이 가능하다. 이는 상속받은 자식클래스만 가능하며 상속 받았기때문에 메모리구조가 같으므로 함수에 코드를 더 덧대어 사용이 가능한 것은 메모리 확장의 개념이다.

 

3. 부모클래스를 가르키는 포인터변수가 자식클래스를 동적할당 받은 주소를 받아 쓸 수 있는 유연함

 

아래는 김성엽 C++ 다형성 실습코드를 바탕으로 연습한 코드다.

 

 

#include <stdio.h>

class Pet
{
public:
virtual void Sound() {}
virtual void Eat() {}
virtual char* Getname() { return NULL; }
virtual Pet* Create() { return NULL; }
};

class Dog : public Pet
{
public:
virtual void Sound() { printf("멍멍\n"); }
virtual void Eat() { printf("뼈다귀\n"); }
char* Getname() { return (char*)"개"; }
virtual Pet* Create() { return new Dog; }
};

class Cat : public Pet
{
public:
virtual void Sound() { printf("야옹\n"); }
virtual void Eat() { printf("생선\n"); }
char* Getname() { return (char*)"고양이"; }
virtual Pet* Create() { return new Cat; }
};

class Mouse : public Pet
{
public:
virtual void Sound() { printf("찍찍\n"); }
virtual void Eat() { printf("치즈\n"); }
char* Getname() { return (char*)"쥐"; }
virtual Pet* Create() { return new Mouse; }
};
// 펫이 늘어날 수 록 변화에 대처, 또한 간결한 코드를 위함
#define MAX_PET 3
Pet* gp_pet_table[MAX_PET] = { new Dog, new Cat, new Mouse };

 

// 부모클래스에 상속된 자식클래스들도 사용할 수 있는 함수

// 아래 선언된 전역변수들 또한 매개변수를 Pet *으로 받으므로 마찬가지

void AddPet(Pet* ap_list[], int* ap_count)
{
int select = 0;
printf("Add Pet - ");
for (int i = 0; i < MAX_PET; i++) {
printf("%d -> %s", i, gp_pet_table[i]->Getname());
}

printf("\nSelect: ");
scanf_s("%d", &select);

if (select >= 0 && select < MAX_PET) {
// 사용자가 선택한 애완동물을 표준 테이블을 사용하여 생성한다.
ap_list[*ap_count] = gp_pet_table[select]->Create();
(*ap_count)++;
}else printf("Invalid Select!!");
}

// 애완 동물의 소리를 출력하는 함수
void PetSound(Pet* ap_list[], int pet_count)
{
for (int i = 0; i < pet_count; i++) ap_list[i]->Sound();
}

void PetEat(Pet* ap_list[], int pet_count)
{
for (int i = 0; i < pet_count; i++) ap_list[i]->Eat();
}

int main()
{
// 애완 동물을 저장할 배열. 다형성을 사용하기 때문에
// Dog, Cat, Mouse으로 구분하지 않고 Pet으로 통일해서 관리함
Pet* p_list[20];
// 애완 동물의 수를 저장할 변수
int pet_count = 0, select = 0;

while (select != 4) {
printf("[ Menu ]\n");
printf("1. Add\n");
printf("2. Sound\n");
printf("3. Eat\n");
printf("4. Exit\n");
printf("Select : ");
scanf_s("%d", &select);

if (select == 1)AddPet(p_list, &pet_count);
else if (select == 2)PetSound(p_list, pet_count);
else if (select == 3)PetEat(p_list, pet_count);
}
// 관리하던 애완 동물의 정보를 제거한다.
for (int i = 0; i < pet_count; i++) delete p_list[i];
// 애완 동물의 기준 테이블에 할당된 객체를 제거한다.
for (int i = 0; i < MAX_PET; i++) delete gp_pet_table[i];

return 0;
}

 

 

아래는 이 코드를 짜면서 실수한 것들이다.

 

1.  //if (select == 0) ap_list[(*ap_count)] = new Dog;
//else if (select == 1) ap_list[(*ap_count)] = new Cat;
//else if (select == 2) ap_list[(*ap_count)] = new Mouse;
//else printf("Do again!\n");

//(*ap_count)++;

if (select >= 0 && select < MAX_PET) {
// 사용자가 선택한 애완동물을 표준 테이블을 사용하여 생성한다.
ap_list[*ap_count] = gp_pet_list[select]->CreatePet();
(*ap_count)++;
}
else printf("Invalid Select!!");

:if문을 너무 많이 돌게 해놓음

2.  for (int i = 0; i < MAX_PET; i++) {
printf("%d - %s\n", i, gp_pet_list[i]->GetName());

// printf("select : ");
// scanf_s("%d", &select);
}
printf("select : ");
scanf_s("%d", &select);

: scanf_s를 쓸데없이 많이 돌게 해놓음. 그리고 scanf_s()인자를 제대로 확인 안해서
sizeof를 넣으며 오류가 났었음

3.
int main()
{
Pet *pet_list[20];
int p_count=0, select;;

while (1) {
printf("[ Menu ]\n");
printf("1. Add\n");
printf("2. Sound\n");
printf("3. Eat\n");
printf("4. Exit\n");
printf("select : ");
scanf_s("%d", &select);

if (select == 1) AddPet(pet_list,&p_count);
else if (select == 2)PetSound(pet_list, p_count);
else if (select == 3)PetEat(pet_list, p_count);
else break;
}
}

처음 클래스 객체포인터배열 선언할때 Pet pet_list[20]으로 선언했다.
왜? AddPet함수에 있는 Pet을 가르키는 일차원포인터매개변수가 main함수에 있는
Pet_list의 주소를 가르켜서 그 주소에서 Dog 든 Cat이든 Mouse든 new 동적할당
해주는 줄 알았는데

main함수의 Pet을 가르키는 일차원포인터배열과 
AddPet함수에 Pet을 가르키는 일차원 포인터배열과 가르키는 곳이 같아야 동적할당
할 수 있나보다..

근데 C에서 동적할당할때는 동적할당해주는 함수에서 이차원포인터로 할당받았는데..
아 그때는 

흐흐 이유를 알았다.

부모클래스에서 상속받은 자식클래스는 함수를 오버라이딩할 수 있다. 그건 메모리
구조가 똑같은데에다가 메모리를 확장시켜 함수를 더 추가하는 것이다.

main에서 Pet pet_list[20]로 단지 선언한다면 Pet클래스 밖에 쓸 수 없다.
Pet *pet_list[20]을 써야 Pet을 가르키는 포인터가 자식클래스인 Dog, Cat, Mouse등을
가르키고 다형성으로 사용할 수 있는 것이다.

 

'C, C++' 카테고리의 다른 글

2차원 메모리 동적할당 (C++)  (0) 2020.08.27
오버라이딩(Over riding)  (0) 2020.08.24
레이달리오 올웨더포트폴리오(2)  (0) 2020.08.23
레이달리오 올웨더포트폴리오(1)  (0) 2020.08.23
도서대여프로그램 with C  (0) 2020.08.21

댓글