본문 바로가기

Programming/C&CPP

다형성과 가상함수

반응형

상속에서 중요한 사실은 부모는 자식을 가리킬 수 있다는 것입니다.

즉, 부모 클래스 B가 자식 클래스 D를 가리킬 수 있다는 말입니다.

하지만 이런 방법은 부모에 없는 자식 멤버는 사라진다는 문제점이 있습니다.

부모가 수용할 수 있는 것이 없기 때문에 버려지게 되는 것입니다.

그리고 역으로 B = D는 될 수 있지만 D = B는 성립하지 않습니다.

다음의 코드를 보도록 하겠습니다.

#include <iostream>
using namespace std;

class Base
{
public:
	void Output()
	{
		cout << "Base::Output() called" << endl;
	}
};

class Derived : public Base
{
public:
	void Output()
	{
		cout << "Derived::Output() called" << endl;
	}
};

int main()
{
	Base b;
	Derived d;

	b.Output();
	d.Output();
}

실행시켜 보면 다음과 같이 정확하게 출력되는 것을 알 수 있습니다.

위에서 부모가 자식을 가리킬 수 있다고 했으니 코드를 살짝 수정해 보겠습니다.

main() 함수 부분을 수정해보도록 하겠습니다.

int main()
{
	Base b, *pB;
	Derived d;

	pB = &b;
	pB->Output();
	pB = &d;
	pB->Output();
}

부모는 자식을 가리킬 수 있으니 문제가 없는 코드이며 처음과 동일한 출력을 기대할 것입니다.

하지만 실제는 다음과 같이 출력됩니다.

예상한 것과는 다른 출력 화면을 보일 것입니다.

부모의 포인터가 실제로는 자식클래스의 객체를 가리키기 때문에

Derived::Output()이 호출되는 것을 기대하고 코드를 작성할 것입니다.

하지만 위와 같이 출력되는 이유는 포인터의 타입이 정해진 시점에 이미 어떤 멤버 함수를 호출할 지가

결정이 되기 때문입니다.

포인터가 무엇을 가리키든 상관없이 이미 이 포인터가 부모타입(Base)이기 때문에

호출되는 함수도 부모의 것으로 정해져있다는 것입니다.

제대로 된 결과를 얻기 위해서 사용하는 방법이 바로 가상함수입니다.

함수의 리턴타입 앞에 virtual이라는 키워드를 붙여주면 가상함수가 됩니다.

부모 클래스에만 virtual을 붙여주면 되지만, 보통은 자식 클래스에도 붙여서 명시합니다.

C++11에서는 override라는 키워드가 추가되서 명시적으로 가상함수를 상속받을 수 있습니다.

아래의 링크에서 확인이 가능합니다.

2014/12/21 - [Programming/C++11&14] - [C++11] final과 override

virtual 키워드를 붙여주면 우리가 원하는데로 값이 출력되는 것을 볼 수 있습니다.

가상함수는 정적 결합(많이 들어본 용어일 것입니다. 정확히는 링킹시에 결합입니다.)을

하지 않고 동적 결합(실행 중에 결정됩니다.)을 사용합니다.

그렇기 때문에 상황에 따라 호출할 멤버 함수를 알아야 합니다.

이것을 알 수 있게 만들어주는 방법  중의 하나는 vtable을 이용하는 것입니다.

vtable은 호출되는 함수의 목록이라고 할 수 있습니다.

그리고 숨겨진 멤버 변수를 하나 추가시켜서 그 변수가 vtable을 가리키게 하는 것입니다.

이런 방식으로 멤버 함수를 동적 결합시킬 수 있습니다.

가리키는 클래스가 달라져도 숨겨진 멤버 변수가 vtable을 가리키고 있기 때문에

vtable을 참조해서 호출할 수 있기 때문에 클래스는 다형성을 확보하게 됩니다.

즉, 같은 함수라도 다른 기능을 하는 게 가능합니다.

가상함수는 이렇게 동적으로 결합시켜서 실제 가리키는 클래스의 함수를 실행하게 합니다.

또한, virtual 리턴타입 함수명(인자) = 0의 가상함수를 만들면 순수 가상함수가 됩니다.

이렇게 만들어두면 자식 클래스는 반드시 이 가상함수를 재정의해서 사용해야 하는

제약이 생기게 됩니다.

가상함수는 COM(Component Object Model)의 기반이 되기도 합니다.

이렇게 하나 이상의 순수 가상함수를 가지는 클래스를 추상 클래스라고 합니다.

추상 클래스는 인스턴스를 생성할 수 없습니다.

반드시 상속을 해서 자식 클래스에서 실체를 만들어준 후에야 사용이 가능합니다.

가상함수는 중요한 개념 중에 하나이기 때문에 C++에서 반드시 알아야 하는 개념 중 하나입니다.

반응형