오늘은 Virtual 함수 가상 함수에 대해 공부하도록 하겠습니다.
가상 함수란?
- 기본 클래스 내에서 선언되는 파생 클래스에 의해 재정의되는 맴버함수
가상 함수를 호출하고 파생 클래스의 함수를 실행할 수 있습니다.
주로 실행시간에 함수의 다형성을 구현하는데 사용됩니다.
가상 함수는 기본 클래스내에 Virtual 키워드로 함수를 선언합니다.
가상 함수 선언에는 몇가지 규칙이 존재합니다.
1. 클래스의 공개(public) 섹션에 선언합니다.
2. 가상 함수는 정적(static)일 수 없으며 다른 클래스의 친구(friend) 함수가 될 수도 없습니다.
3. 가상 함수는 실행시간 다형성을 얻기위해 기본 클래스의 포인터 또는 참조를 통해 접근(access)해야 합니다.
4. 가상 함수의 프로토타입(반환형과 매개변수)은 기본 클래스와 파생 클래에서 동일합니다.
5.클래스는 가상 소멸자를 가질 수 있지만 가상 생성자를 가질 수 없습니다.
코드
#include<iostream>
using namespace std;
class Base
{
public :
void print()
{
cout << "base" << endl;
}
};
class child : public Base
{
public:
void print()
{
cout << "child" << endl;
}
};
int main()
{
Base* b;
child c;
b = &c;
b->print();
}
이런 경우에는 Base에 실제 객체는 child로 가있습니다.
하지만 virtual이 선언이 안되있으면 Base 포인터는 이미 컴파일에 의해 자기 자신의 print를 호출하게됩니다.
하지만 이렇게 바꾼다면 어떤 현상이 벌어질가요?
#include<iostream>
using namespace std;
class Base
{
public :
virtual void print()
{
cout << "base" << endl;
}
};
class child : public Base
{
public:
void print()
{
cout << "child" << endl;
}
};
int main()
{
Base* b;
child c;
b = &c;
b->print();
}
이러한 경우에는 virtual이 선언이 되있으므로 런타임에 의하 그 값이 결정이 납니다.
이러한 결과를 나타내는 이유는 가상 함수 테이블이라는 것인데요
virtual을 선언을 하게 되면 가상 함수테이블을 만들어 함수내에 가상 함수 포인터를 담게 됩니다.
그 가상 함수 포인터는 각각 런타임에 해당 클래스 함수 주소를 할당하여 관리하고있습니다.
처음에 new를 통해 힙 동적 할당을 할 경우 가상함수 태이블에 가상 함수 포인터 는 base에 print 를 가르키고있습니다. 이 또한 런타임에 동적으로 저장해줍니다.
그 다음 b가 c를 가르킬때는 가상 함수 테이블에 가상 함수 포인터는 child에 print 를 가르키고 있습니다.
또한 저 코드는 매우 위험한 코드입니다. new를 하여 동적할당을 했고 바로 child인 c를 가르키면 동적할당된 메모리가 지워지지 않았기 때문에 메모리 누수가 생깁니다. Delete를 생활하 합시다.
'개발자 면접 공부 > C-C++' 카테고리의 다른 글
C++ 캐스팅의 종류 (0) | 2022.07.14 |
---|---|
C++ RTTI 에 대해 (0) | 2022.07.14 |
C++ 순수 가상 함수(추상 클래스) (0) | 2022.07.12 |
C++ 포인터(Pointer) 레퍼런스(Reference) 차이 (0) | 2022.07.11 |
댕글링 포인터(Dangling Pointer) (0) | 2022.07.11 |