c++/상속과 다형성

[C++] 가상함수의 사용

TIM_0529 2023. 1. 16. 09:51
반응형

클래스의 상속관계에서 부모의 함수를 오버라이딩 하여 사용할 때가 있습니다.

만약 그 함수의 객체를 포인터로 만들었을 때 문제가 생길 수 있습니다. 다음의 코드를 보면서 이해해 보겠습니다.

class First
{
public:
	 void SimpleFunc() { cout << "First" << endl; }
};

class Second : public First
{
public:
	 void SimpleFunc() { cout << "Second" << endl; }
};

class Third : public Second
{
public:
	 void SimpleFunc() { cout << "Third" << endl; }
};
int main() {
	Third* ptr3 = new Third();
	Second* ptr2 = ptr3;
	First* ptr1 = ptr2;

	ptr1->SimpleFunc();
	ptr2->SimpleFunc();
	ptr3->SimpleFunc();
}

위 코드의 결과는 다음과 같습니다.

언뜻 보면 정상적인 결과로 보입니다. 하지만 이것이 문제가 되는 이유는 ptr3는 Third 클래스를 가리키는 포인터로 생성이 되었으니 ptr3 -> SimpleFunc() 했을 때 Third 가 나오는 게 정상입니다. 하지만 ptr2와 ptr1 은 객채의 생성은 Second와 First 클래스로 생성이 되었습니다. 하지만 포인터 객체 이므로 서로 가리키는 클래스가 각각

ptr2 -> ptr3 ( Third) 

ptr1 -> ptr2 ( ptr3 -> Third 클래스 ) 가 됩니다. 하지만 

SimpleFunc() 함수는 각각 생성된 클래스에 있는 함수가 불러와졌습니다. 

문제없이 출력이 된것처럼 보이지만 사실 논리상 맞지 않습니다.

이러한 로직 에러를 방지하기 위해 C++에 있는 개념이 가상함수입니다.

 

예를 통해서 가상함수에 사용을 확인해 보겠습니다.

 

class First
{
public:
	 virtual void SimpleFunc() { cout << "First" << endl; }
};

class Second : public First
{
public:
	virtual void SimpleFunc() { cout << "Second" << endl; }
};

class Third : public Second
{
public:
	virtual void SimpleFunc() { cout << "Third" << endl; }
};
int main() {
	Third* ptr3 = new Third();
	Second* ptr2 = ptr3;
	First* ptr1 = ptr2;

	ptr1->SimpleFunc();
	ptr2->SimpleFunc();
	ptr3->SimpleFunc();
}

실행결과는 다음과 같습니다.

가상함수를 사용하면 포인터 클래스 객채 생성 시 클래스 타입이 아닌 포인터가 가리키는 클래스를 할당받아 그 객체에 함수나 멤버 변수에 참조를 하게 해주는 기능입니다. 

 

반응형

'c++ > 상속과 다형성' 카테고리의 다른 글

[C++] 객체 포인터의 참조관계  (0) 2023.01.15