C++ - Virtual 전파
이 Box 클래스를 public 계승해도 안전할까?
class Box : public Object {
public:
Box();
~Box();
};
정답은…이 정보만으로는 뭐라고 말할 수 없다 이다.
얼핏 보면 안 되다고 느끼는 사람도 많을 걸로 생각한다.특히 c++를 좀 알게 되었을 때의 사람은 우선 소멸자에 눈이 가지 않을까 생각한다.
소멸자 앞에 virtual이 붙지 않았다. virtual가 아닌 소멸자는 계승해서는 안 된다는 것은 c++에서 처음에 배우는 것중 하나이다.
좀 더 정보를 더해서, Object 클래스의 정의도 보자.
class Object {
public:
virtual ~Object();
};
virtual이 정의된 소멸자가 정의되고 있다.
이것으로 분명하다. Box는 public 계승해도 안전하다.
“Box를 public계승해도 안전”이라는 표현을 더 자세히 쓰면 “Box를 계승한 클래슬 new로 생성하고, 그 포인터를 Box 혹은 Object의 포인터에 넣어 delete를 불러도 안전”이라는 것이다.
class MyBox:public Box{
public:
MyBox();
~MyBox();
};
int main(){
Box*box=new MyBox;
delete box;//OK 문제 없이 MyBox의 소멸자를 호출
Object obj=new MyBox;
delete obj; //OK 이것도 문제 없이 MyBox의 소멸자를 호출
return 0;
}
Object 클래스의 소멸자에 virtual이 붙어 있어 Object를 public 계승하는 모든 클래스의 소멸자는 암묵적으로 virtual 지정이 붙는다.
C++는 기저 클래스에서 virtual로 정의된 메서드는 파생처에서도 빠짐없이 virtual이 된다.
class Super{
public:
Super(){}
virtual~Super(){}
public:
virtual void func1(){}
virtual void func2(){};
virtual void func3()=0;
};
class Sub:public Super{
public:
Sub(){}
~Sub(){}//이는 암묵적으로 virtual
public:
void func1(){};//이것도 암묵적으로 virtual
void func2(){};//이것도 암묵적으로 virtual
void func3(){};//이것도 암묵적으로 virtual
};
예전에는 파생처의 메소드에 virtual을 달아서 계승자의 메소드를 오버라이드 하고 있다는 것을 알려주는 방법이 있었지만 지금은 c++11에서 추가된 override 키워드가 있으니 이것을 사용한다.
class Super{
public:
Super(){}
virtual~Super(){}
public:
virtual void func1(){}
virtual void func2(){};
virtual void func3()=0;
};
class Sub:public Super{
public:
Sub(){}
~Sub(){}
public:
void func1()override{}//오버라이드 한 것이 명쾌
void func2()override{}//오버라이드 한 것이 명쾌
void func3()override{}//오버라이드 한 것이 명쾌
void func4()override{}//에러!기저 클래스에 없는 메소드 이름!
};
오버라이드 한다는 의사가 뚜렷해지면서 더 가독성이 높은 코드이다. 또 메소드 이름을 틀려도 지금까지는 잘못된 이름으로 새로운 메소드가 만들어져서 오류의 온상이 되었지만, override 키워드의 혜택으로 기저 클래스에 없는 메소드 이름을 지정한 경우 에러로 해준다.
정리
- 기저 클래스에서 virtual인 것은 파생처에서는 마음대로 virtual이 된다
- 오버라이드를 명시하기 위해서 c++11에서 추가된 override 키워드를 사용
이 글은 2020-07-27에 작성되었습니다.