IFlyable 같은 인터페이스로 함수 인자를 통일해 다형성을 만드는 예시를 만들 수 있다.아래처럼 부모 둘 다 Move()를 가지고 있으면, 자식에서 Move() 호출이 애매해집니다.
class Object {
public:
void Move() {}
};
class FlySystem {
public:
void Move() {}
};
class Angel : public Object, public FlySystem {
};
int main()
{
Angel a;
// a.Move(); // ERROR: 어느 Move()인지 모호
a.Object::Move(); // 강제로 지정은 가능하지만, 설계가 거칠어지기 쉽다
a.FlySystem::Move();
}
핵심:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 다중 상속 시 이름 충돌/모호성 │
├─────────────────────────────────────────────────────────────────────────────┤
│ Object::Move() FlySystem::Move() │
│ ▲ ▲ │
│ └──────────┬──────────┘ │
│ ▼ │
│ Angel (Move() 호출이 모호해질 수 있음) │
└─────────────────────────────────────────────────────────────────────────────┘
다중 상속이 더 어려워지는 지점은 “상태(멤버 변수)”까지 섞일 때입니다.
virtual 상속 같은 고급 규칙이 추가되어 난이도가 급상승합니다.결론(실전 기준):
인터페이스는 보통 “순수 가상 함수만 가진 타입”으로 설계합니다.
그리고 인터페이스 포인터로 delete 할 수도 있으므로 소멸자는 virtual이 안전합니다.
class IFlyable {
public:
virtual ~IFlyable() = default;
virtual void Fly() = 0;
virtual void Land() = 0;
};
class Angel : public IFlyable {
public:
void Fly() override { /* ... */ }
void Land() override { /* ... */ }
};
void FlyTest(IFlyable& fly)
{
fly.Fly();
fly.Land();
}
int main()
{
Angel a;
FlyTest(a); // “날 수 있는 것”만 받는 API → 타입이 바뀌어도 호출부는 그대로
}
Angel a; a.Move();가 모호해지는 상황은 어떤 구조에서 발생할까?