결론
(1) 인터페이스 클래스를 생성할 때는, base class에서 pure virtual function을 사용할 것.
(2) 인터페이스 클래스 생성 시, 멤버 변수를 정의하지 말 것.
(3) pure virtual function을 사용했다면 반드시 override 해 줄 것!
Pure virtual function 순수 가상 함수, abstact class 추상 클래스란?
pure virtual function: 함수 implementation, 즉 정의 부분이 없는 가상 함수를 말한다.
C++에서는 밑의 형태와 같이 사용할 수 있다.
선언 : Pure virtual function = 0;
이 Pure virtual function을 하나라도 가지고 있는 함수를 abstract 추상 함수라고 한다.
pure virtual function을 하나라도 가지고 있는 추상 클래스는 object 생성이 불가능하다.
이추상적인 함수기 때문에 object처럼 구체적인 것을 만들 수 없는 것이고,
abstract class의 pure virtual function을 호출할 방법이 없기 때문이다.
만약 위 코드와 같이 Pure virtual function을 가진 abstract class인 Animal object를 생성하려고 시도하면 컴파일러가 에러메세지를 띄울 것이다.
반면 derived class인 Cat의 object는 만드는 것이 가능하다.
이 때도, base class의 pure virtual function을 무조건 override를 통해서 implementation 시켜 주어야 한다.
override 해주지 않는다면 오브젝트 생성 시에 컴파일 에러 메세지를 볼 수 있다.
실사용 예시
pure virtual function, abstract class의 함수가 소프트웨어 개발을 편하게 만들어 줄 수 있다.
예를 들어 게임에서 몬스터 클래스를 정의한다고 하면,
(ex)
이렇게 베이스 클래스에서
attack()과 defence()를 pure virtual function으로 만들어 준다면
derived class에서 override하여 이 두가지 함수를 각각 다르게 구현해 줄 수 있다.
아키텍쳐를 관리해 주는 개발자가 베이스 클래스인 Monster class와 그것을 상속받은 Orc, Goblin class를 정의하고,
각 몬스터의 디테일을 만들어 주는 다른 개발자들이 이 몬스터 class를 상속받아서
오크의 공격 특성, 고블린의 특성을 상세하게 implementation 시켜주는 식으로 일하게 되면 효율적인 분업이 가능해지는 것이다.
위와 같이 코드를 짤 때, Pure virtual function을 통해서 베이스 클래스는 인터페이스만 정의하면 되는데,
이런 클래스를 Interface class 인터페이스 클래스라고 이야기한다.
Interface class를 만들 때 중요한 점은
(1) 내부에 implementation을 써주지 않고,
(2) member variable 또한 써주지 않는 것이
유연한 소프트웨어 구조를 가져갈 수 있는 팁이다.
Interface Class에 멤버 변수 사용하지 마세요
똑같이 Base class인 Animal class를 만들고
이를 상속받은 Cat class를 만들어 보자.
공통된 기능인 말하는 speak() 함수는 순수가상함수 pure virtual function으로 만들어 주고
이런 식으로 상속받은 Cat class 만들 때는 문제가 없는데,
회사에서 갑자기 돌고래 class를 만들어 달라는 요청이 들어온다!
문제는, base class의 걷기를 모두 정의해 놨는데, 돌고래는 걸을 수 없는 동물이다.
이것을 고치기 위해서 walk override 를 통해 수영을 만들고,
베이스 클래스로 들어와서 virtual로 만들어 주면 해결 가능하긴 하다.
이 뿐만 아니라 다리의 개수도 멤버변수로 정의해 줬는데, 돌고래는 다리도 없다.
그래서 새롭게 finCount 즉 지느러미 개수도 만들어줘야 하는데
문제는 이런 새롭게 정의해 주어야하는 문제 뿐만 아니라
사용하지도 않는 noseLocation, legCount를 돌고래 클래스에선 여전히 상속을 받은 상태이고
돌고래 클래스에서 정의가 되어 있다는 것이다. 쓸데없는 멤버 변수들, 무의미한 데이터들을 가지고 있게 된다.
즉 Derived class에서 필요 없는 데이터가 점점 늘어나게 되고 유지보수가 어렵다는 것이다.
이제 추가로 닭, 거미 등등 여러 클래스를 추가해 달라는 요청이 들어오면 난장판이 될 것이다!
따라서 유지보수가 쉬운 interface class를 만들 때는,
멤버 변수를 전부 없애고
모든 함수를 pure virtual function으로 만드는 것이 더 유연한 인터페이스를 만드는 팁이다.
이렇게 만들면 각 파생 클래스에 맞는 여러 멤버 변수들을 하나씩 자유롭게 만들어 갈 수도 있다.
그리고 인터페이스 클래스에서 정의된 모든 pure virtual function은 override를 통해서 정의해 주어야 한다는 것!
다만, 유연한 구조는 가져갈 수 있지만 중복이 되는 파트는 derived class에서 매번 정의해 주어야 하는 번거로움이 있다.
이럴 땐 interface class와 따로 implementation class를 만들어 주고 두개의 class를 동시에 상속 받으면
유지보수가 좋은 interface의 장점과 코드 재사용의 장점을 모두 가져갈 수 있는데 이 때 다중상속의 개념이 들어간다.
'모던C++ > 상속관계 Inheritance' 카테고리의 다른 글
8. Dynamic Cast _C++ (0) | 2022.09.02 |
---|---|
7. Virtual Inheritance 가상 상속_C++ (0) | 2022.09.01 |
6. 다중 상속 multiple inheritance _ C++ (0) | 2022.09.01 |
4. Virtual Table, Virtual Function _ C++ (0) | 2022.08.31 |
3. 가상 함수 Virtual Function _ C++ / Dynamic Polymorphism (0) | 2022.08.23 |
2. 접근 권한 키워드 - public, private, protected, 파생 클래스 _ C++ (0) | 2022.08.23 |
1. Inheritance 상속이란? _ C++ (0) | 2022.08.23 |