본문 바로가기

C++

[C++] 가상 함수(Virtual function)와 소멸자 가상화

가상 함수란?

가상 함수(Virtual function)는 virtual 예약어를 붙여서 선언한 메서드이다. 가상 함수는 과거의 정의가 완전히 무시된다는 것이 특징이다.

 

사용 방법은 다음과 같다.

virtual 반환형식 메서드이름

 

함수앞에 virtual 예약어만 붙여주면 된다.

 

#include <iostream>
using namespace std;

//부모 클래스
class PClass
{
public:
	//가상 함수
	virtual void printNum()
	{
		cout << "PClass num : " << num << endl;
	}

	void TestFunc()
	{
		cout << "TestFunc()" << endl;
		printNum();
	}

protected:
	int num = 10;
};

//파생 클래스
class CClass : public PClass
{
public:
	//가상 함수 재정의
	virtual void printNum()
	{
		cout << "CClass: " << num*2<< endl;
	}
};

int main()
{
	CClass a;	//파생 클래스 객체생성
	a.printNum();

	PClass& b = a;
	b.printNum();

	a.TestFunc();

	return 0;
}

 

결과값:

CClass: 20	//a.printNum()의 결과
CClass: 20	//b.printNum()의 결과
TestFunc()	//a.TestFunc()의 결과
CClass: 20

 

virtual 예약어를 통해 기존의 부모 클래스에서 정의된 메소드가 완전히 오버라이드된 것을 확인할 수 있다. 가상 함수는 재정의된 메소드가 있다면 그 함수를 호출하는 것이다.

 

또한, 상 함수는 일반 메소드와 달리 참조 형식과 관계없이 실 형식의 메소드를 호출한다. 만약, 부모 클래스에서 virtual 예약어를 지운다면 b.printNum(); 코드에 의해 'PClass : 10'이라는 결과가 나왔을 것이다. 일반 메소드는 참조 형식에 의해 어떤 메소드가 호출되는지 결정되기 때문이다.

 

마지막으로, TestFunc() 함수에서 printNum() 함수를 호출하는데 이 printNum()은 가장 마지막에 재정의된 함수를 호출한다.

 


부모 클래스에 대한 포인터나 참조자로 파생 클래스 인스턴스를 참조할 수 있다.

 

부모클래스 *a = new 파생클래스;

 

#include <iostream>
using namespace std;

//부모 클래스
class PClass
{
public:
	PClass() { name = new char[10]; }
	~PClass() 
	{ 
		cout << "~PClass()" << endl;
		delete name;
	}

private:
	char* name;
};

//파생 클래스
class CClass : public PClass
{
public:
	CClass() { age = new int; }
	~CClass()
	{
		cout << "~CClass()" << endl;
		delete age;
	}
private:
	int* age;
};

int main()
{
	PClass* a = new CClass;

	delete a;

	return 0;
}

 

결과값:

~PClass()

 

이 코드에는 문제점이 있다. 부모 클래스의 소멸자 호출은 이루어지나 파생 클래스의 소멸자는 호출되지 않는다. 즉, 참조 형식의 소멸자만 호출되고 실 형식의 소멸자는 호출되지 않는다.

 

소멸자를 가상화하여 해결할 수 있다.

virtual ~PClass()
{
	cout << "~PClass()" << endl;
	delete name;
}

 

결과값:

~CClass()
~PClass()

 

*상속 관계에서 가상 함수는 한 번 가상 함수면 영원히 가상 함수다. 즉 부모 클래스에서 가상 함수이면 파생 클래스에서 virtual 예약어를 사용하지 않더라도 자동으로 가상화된다.