그다지 책에는 설명이 안되어있는 virtual 키워드...
솔직히 일본에서 일할때 그쪽에선 특별히 뭔가 상속하면서 클래스를 만드는걸 꺼려서해 그런지...
virtual 키워드를 왠만하면 쓰지 않았기 때문에 프로그래밍으로 밥먹고 사는 저도 가물가물한 놈입니다.
잡설은 그만하고
virtual 과 override 차이만 얘기 합니다.
만약
/************************************************************************/
/*상위클래스 */
/************************************************************************/
class upClass
{
public:
void print(){
cout<<"up class"<<endl;
}
};
/************************************************************************/
/* 상속 A */
/************************************************************************/
class aClass : public upClass
{
public:
void print(){
cout << "aClass"<<endl;
}
};
/************************************************************************/
/* 상속 B */
/************************************************************************/
class bClass : public upClass
{
public:
void print(){
cout <<"bClass"<< endl;
}
};
이렇게 해놓았다면
AClass 클래스를 만들어 print()를 호출할때 상속 받은 UpClass의 print함수가 아닌
AClass의 print 함수를 불러오는건 프로그래머로썬 상식입니다.
그리고 이걸 AClass함수가 원래 UpClass를 상속해 존재한 같은 이름의 print 함수를 덮어 씌었기 때문에 override라고 합니다.
보통 프로그래밍 할땐 문제가 없지만
만약 경우에 따라 A,B클래스를 따로 부르고 싶을땐 문제가 발생합니다.
예를들어
//메인 함수
void main()
{
upClass *ptr; //aClass를 부를지, bClass를 부를지 모르니까 둘의 공통 분모 클래스의 포인터 생성
int num = 100; //적당한 조건문
//조건에 따라서
if(num < 10){
ptr = new aClass(); //aClass를 생성
}else{
ptr = new bClass(); //bClass를 생성
}
ptr->print(); //위 조건에 따라 분기된 클래스의 print()함수를 실행
delete ptr;
}
이렇게 하면
이런 결과가 나옵니다.
분명히 조건에 따라 bClass를 만들었는데 bClass의 print에서 정의한 cout << "bClass" << endl; 의 결과가 나오지 않습니다.
이런 문제를 해결하기 위해 쓰는것이 virtual 키워드 입니다.
컴파일러에게, 만약 이녀석 함수가 불러질때, 상속된 녀석이 이 함수를 오버라이딩 했을 가능성이 있으니 상속된 함수라면
정말 오버라이딩 했는지 확인한뒤 처리 하란 뜻입니다.
즉, 위의 상위 클래스에서 virtual를 추가하고 다시 컴파일 해보면
/************************************************************************/
/*상위클래스 */
/************************************************************************/
class upClass
{
public:
virtual void print(){
cout<<"up class"<<endl;
}
};
의도한 대로 bClass에서 생성된 print 가 실행 되었습니다.
추가로, 가끔 소멸자에 virtual 키워드를 붙이라고 하는걸 들어본 적이 있을껍니다.
그 이유는 위와 같이, 소멸자에 virtual 를 붙이지 않고 단순히
upClass *a = new bClass 로 할때
a가 소멸할시 소멸자는 upClass의 소멸자를 호출하는거지 , new 로 선언한 bClass 의 소멸자가 불러오지 않기 때문이죠.
virtual 를 소멸자에 선언하면, 당연히 bClass 의 소멸자가 실행되고 upClass의 소멸자가 실행됩니다.
이게 중요한 이유는 의도치 않는 메모리 누수가 발생하기 떄문이죠.
특히 서버 프로그래밍경우 메모리 관리가 엄청 중요합니다. (이것때문에 서버가 크리티컬로 다운되면 게임 전체가 stop이죠... ㅠㅠ)