티스토리 뷰

C++

[C++] 가상함수 (Virtual)

루우지 2018. 5. 14. 10:55

가상함수


가상함수는 virtual 예약어를 앞에 붙여서 선언한 메서드를 말한다. 따라서 가상 함수라는 말은 메서드라는 말을 내포하여, 이 가상 함수는 기본적으로 '자기 부정'을 전제로 작동한다. 달리 말해 파생 형식 에서 메서드를 재정의하면 가거의 정의가 완전히 무시된다는 특징이 있다. java와 비교하자면 자식클래스에서의 부모클래스의 함수를 오버라이드 하는 개념으로 이해했다. 하지만 재정의 이후에 호출하는 과정에서는 자바와는 조금 다른 방식을 취한다.


가상함수는 다음과 같이 선언한다.

virtual void PrintData();


// #include "stdafx.h" #include

using namespace std; class CMyData { public: virtual void PrintData() { cout << "CMyData: " << m_nData << endl; } void TestFunc() { cout << "***TestFunc()***" << endl; PrintData(); cout << "****************" << endl; } protected: int m_nData = 10; }; class CMyDataEx : public CMyData { public: virtual void PrintData() { cout << "CMyDataEx: " << m_nData * 2 << endl; } }; int main() { CMyDataEx a; a.PrintData(); CMyData &b = a; b.PrintData(); a.TestFunc(); }


위의 예제에서 CMyData::PrintData() 함수를 가상 함수로 선언했는데, 이 함수는 내부 멤버 데이터인 m_nData의 값을 출력한다. 그리고 32번 행에서 이 PrintData() 함수를 재정의했다. 여기까지는 기존의 일반 베서드를 재정의한 것과 크게 다르지 않기 때문에 호출하게 되면 CMyDataEx 클래스의 PrintData() 메서드를 호출한게 된다.



CMyData  &b = a;

b.PrintData();

재밌는 코드가 등장하게 되는데 실형식은 CMyDataEx이며 참조 형식은 기본 클래스인 CMyData에 속한 참조자 b가 선언됐다. 그리고 b를 통해 PrintData()를 호출했습니다. 일반 메서드의 경우 실 형식은 중요하지 않고 참조 형식이 무엇인지에 따라 어떤 메 서드가 호출되는지 결정이 났지만 가상함수는 다르다. 가상 함수는 일반 메서와 달리 참조 형식이 무엇이든 실 형식의 메서드를 호출한다.


"일반 메서드는 참조 형식을 따르고, 가상함수는 실 형식을 따른다.



	
void TestFunc()
{
		cout << "***TestFunc()***" << endl;

		PrintData();
		cout << "****************" << endl;
}


PrintData(); 는 누구를 호출할까? TestFunc() 함수는 기본 클래스인 CMyData의 멤버이다. 그러므로 위의 PrintData()는 기본적으로 CMyData 클래스의 PrintData() 함수를 말하는 것이다. 그런데 문제는 PrintData() 함수가 '가상 함수'라는 사실이다. 이렇게 되면 지금 PrintData() 함수는 '미래'에 재정의된 함수일 수 있다.

만일 파생형식(자식)에서 PrintData() 가상 함수를 재정의한다면 위의 PrintData()는 미래의 함수를 호출하는 것이다.


가상함수


가상함수는 virtual 예약어를 앞에 붙여서 선언한 메서드를 말한다. 따라서 가상 함수라는 말은 메서드라는 말을 내포하여, 이 가상 함수는 기본적으로 '자기 부정'을 전제로 작동한다. 달리 말해 파생 형식 에서 메서드를 재정의하면 가거의 정의가 완전히 무시된다는 특징이 있다. java와 비교하자면 자식클래스에서의 부모클래스의 함수를 오버라이드 하는 개념으로 이해했다. 하지만 재정의 이후에 호출하는 과정에서는 자바와는 조금 다른 방식을 취한다.


가상함수는 다음과 같이 선언한다.

virtual void PrintData();


// #include "stdafx.h" #include

using namespace std; class CMyData { public: virtual void PrintData() { cout << "CMyData: " << m_nData << endl; } void TestFunc() { cout << "***TestFunc()***" << endl; PrintData(); cout << "****************" << endl; } protected: int m_nData = 10; }; class CMyDataEx : public CMyData { public: virtual void PrintData() { cout << "CMyDataEx: " << m_nData * 2 << endl; } }; int main() { CMyDataEx a; a.PrintData(); CMyData &b = a; b.PrintData(); a.TestFunc(); }


위의 예제에서 CMyData::PrintData() 함수를 가상 함수로 선언했는데, 이 함수는 내부 멤버 데이터인 m_nData의 값을 출력한다. 그리고 32번 행에서 이 PrintData() 함수를 재정의했다. 여기까지는 기존의 일반 베서드를 재정의한 것과 크게 다르지 않기 때문에 호출하게 되면 CMyDataEx 클래스의 PrintData() 메서드를 호출한게 된다.



CMyData  &b = a;

b.PrintData();

재밌는 코드가 등장하게 되는데 실형식은 CMyDataEx이며 참조 형식은 기본 클래스인 CMyData에 속한 참조자 b가 선언됐다. 그리고 b를 통해 PrintData()를 호출했습니다. 일반 메서드의 경우 실 형식은 중요하지 않고 참조 형식이 무엇인지에 따라 어떤 메 서드가 호출되는지 결정이 났지만 가상함수는 다르다. 가상 함수는 일반 메서와 달리 참조 형식이 무엇이든 실 형식의 메서드를 호출한다.


"일반 메서드는 참조 형식을 따르고, 가상함수는 실 형식을 따른다.



	
void TestFunc()
{
		cout << "***TestFunc()***" << endl;

		PrintData();
		cout << "****************" << endl;
}


PrintData(); 는 누구를 호출할까? TestFunc() 함수는 기본 클래스인 CMyData의 멤버이다. 그러므로 위의 PrintData()는 기본적으로 CMyData 클래스의 PrintData() 함수를 말하는 것이다. 그런데 문제는 PrintData() 함수가 '가상 함수'라는 사실이다. 이렇게 되면 지금 PrintData() 함수는 '미래'에 재정의된 함수일 수 있다.

만일 파생형식(자식)에서 PrintData() 가상 함수를 재정의한다면 위의 PrintData()는 미래의 함수를 호출하는 것이다.



------------- 실행 화면 -------------


CMyDataEx: 20

CMyDataEx: 20

***TestFunc()***

CMyDataEx: 20

****************

계속하려면 아무 키나 누르십시오 . . .