OOP Summary
요구사항
- Animal이라는 기본 클래스를 정의 합니다. →
class Animal{}
- Animal 클래스에는
makeSound()라는 순수 가상 함수를 포함합니다. → virtual void makeSound() = 0;
- Animal 클래스를 상속받아 다양한 동물 클래스를 생성합니다. 예) Dog, Cat, Cow →
class Dog : public Animal
- 각 클래스에서 makeSound()함수를 재정의하여 해당 동물의 소리를 출력합니다. →
override
- 메인 함수에서 Animal 타입의 포인터 배열을 선언합니다. →
Animal* animals[3]
- Dog, Cat, Cow 자료형의 변수를 선언하고, 배열에 저장해봅니다. →
Dog my Dog();
- Animal 배열을 반복문으로 순회하면서 각 동물의 울음소리를 내게 합니다. →
for
코드
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void makeSound() = 0;
};
class Dog : public Animal
{
public:
void makeSound() override
{
cout << "Woof!" << endl;
}
};
class Cat : public Animal
{
public:
void makeSound() override
{
cout << "Meow~" << endl;
}
};
class Cow : public Animal
{
public:
void makeSound() override
{
cout << "Moo~" << endl;
}
};
int main()
{
Dog myDog;
Cat myCat;
Cow myCow;
Animal* animals[3] = { &myDog, &myCat, &myCow };
for (int i = 0; i < 3; i++)
{
animals[i]->makeSound();
}
return 0;
}
구현 기능 정리
추상 클래스
virtual void makeSound() = 0;
- 추상 클래스에서 기능하지 않아도 자식 클래스에서 반드시 구현해야 함
- 직접 객체 생성 불가
다형성(Polymorphism)
Animal* animals;은 내가 직접 만든 포인터 변수 이름
Animal 타입의 객체를 가리킬 수 있는 포인터를 만든 것
- 부모 클래스 포인터 하나로 여러 파생 클래스 객체(Dog, Cat 등)를 처리할 수 있음
- 자식 클래스에서
makeSound()를 override
포인터 배열
Animal* animals[3] → 포인터 3개가 들어 있는 배열
- 각각 다른 객체의 주소를 저장해서 다형성을 활용
배열 인덱스
animals[i]->makeSound();
i는 animals 배열의 몇 번째 동물인지를 알려주는 역할
animals[0] → myDog
animals[1] → myCat
animals[2] → myCow
i가 바뀌면서
i == 0 → animals[0]->makeSound(); → "Woof!"
i == 1 → animals[1]->makeSound(); → "Meow~"
i == 2 → animals[2]->makeSound(); → "Moo~"
반복문
- 배열 순회하면서
makeSound() 호출
- 실행 시 실제 객체 타입에 따라 다른 함수 호출됨 (동적 바인딩)
📌 스택 vs 힙
Dog myDog;
- 스택 메모리에 저장
- 포인터 아닌 그냥 스택 객체
myDog.speak();
→ . 연산자 사용해 접근
- 자동으로 생성되고 자동으로 소멸됨
→ main() 함수 끝나면 사라짐
→ delete 필요 없음
- 빠르고 안전함
Animal* myAnimal = new Dog();
- 힙에 Dog 객체 생성
Animal* 로 그 주소를 저장
new 로 만들면 직접 메모리 관리 필요
- 꼭
delete myAnimal; 수동으로 메모리 해제 필요
→ 안 하면 메모리 누수 생김
- 객체를 오래 유지하거나 동적으로 개수 조절할 때 사용됨