C++ Chapter 12.3 : override, final, 공변 반환형
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!
chapter 12. 가상 함수들 : override, final, 공변 변환형
🔔 override
class A
{
public:
virtual void print(int x) { cout << "A" << endl; }
};
class B : public A
{
public:
void print(short x) { cout << "B" << endl; }
}
- print 함수는 virtual 가상 함수이므로 자식 클래스로 하여금 오버라이딩이 될 것을 권장 하는 함수다.
- 자식클래스 B 에서 이를 오버라이딩 했지만 현재 매개 변수 형식이 틀린 상태이다. (int != short)
- 오버라이딩은 리턴타입 + 함수이름 + 매개변수형태 + const 유무까지 전부 똑같아야 한다.
- 따라서 오버라이딩 되지 않았다고 판단 되어 A 클래스의 print 가 실행된다.
- 즉, 오버라이딩 된게 아니라 오버로딩이 됨.
orverride
키워드를 붙여주면 오버라이딩 한 함수라고 강조 해주며 오버라이딩이 제대로 안됐을시 컴파일 에러를 발생시켜 준다.
class A
{
public:
virtual void print(int x) { cout << "A" << endl; }
};
class B : public A
{
public:
void print(short x) override { cout << "B" << endl; } // 에러 💥
}
- void print(short x)
override
- 부모 클래스 중 void print(short x) 라는 함수는 없기 때문에, 즉 파라미터가 틀려서 제대로 오버라이딩 되지 않았다며 컴파일 에러를 발생시킨다.
- void print(int x) override 라고 바꿔주면 에러가 사라질 것.
class A
{
public:
virtual void print(int x) const { cout << "A" << endl; }
};
class B : public A
{
public:
void print(short x) override { cout << "B" << endl; } // 에러 💥
}
- 뒤에 const가 안붙어서 컴파일 에러가 난다.
- void print(short x) const override 라고 바꿔주면 에러가 사라질 것.
오버라이딩은 리턴타입 + 함수이름 + 매개변수형태 + const 유무까지 전부 똑같아야 한다.
🔔 final
final
: 자식 클래스에서 오버라이딩을 못하도록 막아버린다.
class A
{
public:
virtual void print() { cout << "A" << endl; }
};
class B : public A
{
public:
void print() final { cout << "B" << endl; }
}
class C : public B
{
public:
void print() { cout << "B" << endl; } // 에러 💥
}
- A 클래스의 가상함수인 print를 자식인 B 클래스에서 오버라이딩 해주었는데
final
이 붙었다.- 오버라이딩은 이제 B 클래스에서까지가 마지막이고 그 이후 자식 클래스부터는 이 함수를 오버라이딩 할 수 없다.
- B 클래스의 자식인 C 클래스에서 오버라이딩을 시도해서 컴파일러 에러 발생
🔔 공적 반환형(Covariant Return)
리턴 타입이 다른데도 오버라이딩이 되는 경우 👉
this
(자기 자신을 가리키는 포인터)을 리턴하는 함수의 경우.
class A
{
public:
void print()
{
cout << "A" << endl;
}
virtual A* getThis()
{
cout << "A::getThis()" << endl;
return this;
}
};
class B : public A
{
public:
void print()
{
cout << "B" << endl;
}
virtual B* getThis()
{
cout << "B::getThis()" << endl;
return this;
}
};
- 리턴타입이
A*
,B*
로 다르지만- B 는 A 의 자식이기에
B*
타입인 B 의 this는A*
의 성질도 가지고 있기 때문에 this를 리턴하는 함수의 경우 리턴타입이 달라도 오버라이딩이 허용된다.- A 와 B 가 부모 자식 관계이기 때문!
- B 는 A 의 자식이기에
int main()
{
A a;
B b;
A &ref = b;
b.getThis()->print(); // B 출력
ref.getThis()->print(); // A 출력
cout << typeid(b.getThis()).name() << endl; // class B * 출력
cout << typeid(ref.getThis()).name() << endl; // class A * 출력
return 0;
}
- A &ref = b;
- A 타입인
ref
는 B 타입의b
객체를 참조한다.
- A 타입인
- b.getThis()->print();
b
는 B 타입.- B 타입으로 호출하니 B 타입의 getThis() 를 호출한다.
- ref.getThis()->print()
ref
는 A 타입.- A 타입으로 호출하는데 A 타입의 getThis는 가상 함수이다.
- 리턴 타입은 달라도 부모-자식 관계에다가 this를 리턴하므로 오버라이딩이 되어 B 타입의 getThis가 호출된다.
- B 타입의 getThis()가 B* 타입의 포인터(
b
객체의 주소)를 리턴하는데 이를 호출한 `ref`가 A 타입이기 때문에 print()는 A 타입의 print()가 실행된다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기