추상 클래스란
추상 클래스란 순수 가상 함수(pure virtual function)을 선언한 클래스를 말한다.
가상 함수? 순수 가상 함수?
가상 함수란 부모 클래스에서 이를 상속받을 자식 클래스에서 함수를 override 할 수 있도록 만든 함수이다.
virtual void foo();
이렇게 함수 앞에 virtual 이라는 키워드를 사용하여 선언할 수 있다.
순수 가상 함수란 함수의 정의 없이 선언만 한 함수를 말한다.
virtual void foo() = 0;
부모 클래스를 상속한 자식 클래스에서 override 여부를 결정할 수 있는 다른 가상 함수와 다르게 순수 가상 함수는 자식 클래스에서 무조건 override 해주어야 한다.
만약 순수 가상 함수를 가진 부모 클래스, 즉 추상 클래스인 부모 클래스를 상속했음에도 부모 클래스의 모든 순수 가상 함수를 override 하지 않는다면 그 자식 클래스도 추상 클래스가 된다.
객체 생성 불가능
추상 클래스의 경우 자식 클래스로 선언된 객체를 추상 클래스인 부모 클래스로 casting하여 저장하는 것은 가능하지만, 직접적인 객체 생성은 불가능하다.
class A {
public:
virtual void foo() = 0;
};
int main() {
A a; //error
return 0;
}
A가 추상 클래스이기 때문에 A를 생성하려고 하면 에러가 발생한다.
class A {
public:
virtual void foo() = 0;
};
class B : public A {
};
int main() {
A a; //error
B b; //error
return 0;
}
A를 상속하였지만 A의 모든 순수 가상 함수를 override 하지 않은 B도 추상 클래스가 되어 B의 객체 생성을 시도해도 에러가 발생한다.
class A {
public:
virtual void foo() = 0;
};
class B : public A {
void foo() override {
// do something
}
};
int main() {
B b; //ok
return 0;
}
B의 객체 생성을 가능하게 하기 위해서는 A의 순수 가상 함수인 foo()를 B에서 override 해주면 된다.
추상 클래스 활용
추상 클래스는 어떤 경우에 사용해야 할까?
추상 클래스는 객체 지향 프로그래밍에서 코드의 구조를 명확하게 하고, 코드의 재사용성을 높이기 위해서 사용한다. 각 클래스에서 공통적으로 사용하는 기능을 묶어서 추상 클래스에 선언하고, 이를 상속시켜 각 클래스에서 이를 정의하게 되면 이와 비슷한 클래스가 새롭게 필요해졌을 때 함수들을 선언하지 않고 그저 만들어둔 추상 클래스를 상속할 수 있다.
예시
#include <iostream>
using namespace std;
class Dog {
public:
void sound() {
cout << "Bark" << endl;
}
};
class Cat {
public:
void sound() {
cout << "Meow" << endl;
}
};
void makeSound(Dog& dog) {
dog.sound();
}
void makeSound(Cat& cat) {
cat.sound();
}
int main() {
Dog dog;
Cat cat;
makeSound(dog);
makeSound(cat);
return 0;
}
여기 Dog와 Cat라는 클래스가 있고, 둘 다 sound라는 함수를 가지고 있다. 만약 모든 동물의 소리를 내고 싶다면 Dog와 Cat를 따로 실행해야 한다.
또한 Dog와 Cat이외에 새로운 동물이 추가될 때마다 sound()와 makeSound()가 추가될 것이다.
#include <iostream>
using namespace std;
// 추상 클래스
class Animal {
public:
// 순수 가상 함수
virtual void sound() = 0;
};
class Dog : public Animal {
public:
void sound() override {
cout << "Bark" << endl;
}
};
class Cat : public Animal {
public:
void sound() override {
cout << "Meow" << endl;
}
};
void makeSound(Animal* animal) {
animal->sound();
}
int main() {
Dog dog;
Cat cat;
makeSound(&dog);
makeSound(&cat);
return 0;
}
하지만 Animal이라는 추상 클래스에 Dog와 Cat에 공통적으로 존재했던 sound()라는 함수를 순수 가상 함수로 넣은 뒤, Dog와 Cat에서 Animal을 상속하게 한다면 Dog와 Cat 상관없이 Animal을 통해 sound()를 실행시킬 수 있다.
새로운 동물이 추가되어도 Animal을 상속시키면 되고, makeSound()는 아무런 수정 없이 계속 사용 가능하게 된다.
'C++' 카테고리의 다른 글
[C++] 게임 엔진 개발일지 1장 (0) | 2025.01.01 |
---|---|
[C++] 캐스팅(Casting) (0) | 2024.10.16 |