글 작성자: Sowhat_93

C++11 에 override 와 final 키워드가 추가되었다.

아래의 코드를 보도록 하자.

 

1. override

#include <iostream>
class EntityBase
{
public:
virtual void Print() { std::cout << " I am Base !" << std::endl; }
EntityBase () { }
virtual ~EntityBase () { }
};
class EntityTypeA : public EntityBase
{
public:
void Print() { std::cout << "I am Type A Entity !" << std::endl; }
EntityTypeA() { }
virtual ~EntityTypeA() { }
};
class EntityTypeB : public EntityTypeA
{
public:
void Print() { std::cout << "I am Type B Entity !" << std::endl; }
EntityTypeB() { }
virtual ~EntityTypeB() { }
};
int main()
{
EntityBase* p = new EntityTypeB();
p->Print();
}

결과는 "I am Type B Entity" 가 출력된다.

최상위 클래스인 EntityBase 의 함수가 virtual 로 정의 되어 있고,

하위 클래스들이 최상위 클래스의 시그니쳐에 따라 얌전히 재정의 하고있다.

그런데, 만약 다음과 같은 경우라면?

class EntityTypeA : public EntityBase
{
public:
void Print(int A) { std::cout << "I am Type A Entity !" << std::endl; }
EntityTypeA() { }
virtual ~EntityTypeA() { }
};
class EntityTypeB : public EntityTypeA
{
public:
void Print(int A) { std::cout << "I am Type B Entity !" << std::endl; }
EntityTypeB() { }
virtual ~EntityTypeB() { }
};

결과는 " I am Base !" 가 출력된다.

EntityBase* p = new EntityTypeB();
p->Print();

가지고 있는 포인터는 EntityBase 형 포인터이다 때문이다.

가상함수 호출시 실제 객체의 vfptr을 참조하게 되는데,

이때의 Print, 즉 시그니쳐가 void 반환형에 void 인자인 경우를 찾게된다.

없으니 EntityBase의 함수가 호출된다.

이름이 같을 뿐 결국 다른 함수 취급이 되는거다.

여기서 override keyword를 사용해보자.

 

class EntityTypeA : public EntityBase
{
public:
void Print(int A) override { std::cout << "I am Type A Entity !" << std::endl; }
//컴파일 에러.
//override-> 내가 상위클래스의 void Print(int) 를 재상속 한것임을 선언.
//?? 없는데? void Print(void) 인데??
EntityTypeA() { }
virtual ~EntityTypeA() { }
};
class EntityTypeB : public EntityTypeA
{
public:
void Print() override { std::cout << "I am Type B Entity !" << std::endl; }
//무리없이 okay
EntityTypeB() { }
virtual ~EntityTypeB() { }
};

컴파일 에러가 난다.

이름이 같을뿐 함수의 시그니쳐가 다르기 때문이다.

override keyword는 이 함수가 상위 클래스의 가상함수를 재정의 했음을 나타내는데,

컴파일러가 상위 클래스에서 아무리 찾아봐도 없기 때문에 컴파일 오류가 나는 것이다.

override를 붙이던 안붙이던

상위클래스의 가상함수와 하위클래스에서의 함수가 시그니쳐가 같다면 잘 호출 된다.

허나 협업시 명시적으로 override를 했음을 확실시하고 실수를 방지하기 위해 붙이도록 한다.

2. final

하위 클래스에서의 재정의를 막아버린다.

재정의시 컴파일 에러.

class EntityBase
{
public:
virtual void Print() { std::cout << " I am Base !" << std::endl; }
EntityBase () { }
virtual ~EntityBase () { }
};
class EntityTypeA : public EntityBase
{
public:
void Print() final { std::cout << "I am Type A Entity !" << std::endl; }
EntityTypeA() { }
virtual ~EntityTypeA() { }
};
class EntityTypeB : public EntityTypeA
{
public:
void Print() override { std::cout << "I am Type A Entity !" << std::endl; }
//컴파일 에러 !
void Print(int A) { }
//이름만 같을 뿐 별개의 함수.
//컴파일 Okay.
EntityTypeB() { }
virtual ~EntityTypeB() { }
};

 

'C++' 카테고리의 다른 글

[C++] STL Custom Allocator 사용  (0) 2022.04.08
[C++] C++ 11 mutable  (0) 2022.03.28
[C++] new[] , delete[] 오버로딩시 주의 사항.  (0) 2022.03.28
[C++] const lvalue reference, rvalue reference  (2) 2022.03.23
[C++] C++11 constexpr  (0) 2022.03.20