강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

김동현님의 프로필 이미지
김동현

작성한 질문수

홍정모의 따라하며 배우는 C++

12.3 override, final, 공변 반환값

공변반환형 관련 문의 드립니다.

작성

·

36

1

안녕하세요?

 

이번 강의의 마지막 부분에서, 공변반환형 이라는 내용으로 수업을 해주셨는데 내용이 이해가 어렵다보니 생성형 AI의 힘을 빌려서 이해를 해보려고 하다가... Gemini가 수업시간에 교수님께서 알려주신 내용이 틀리다고 대답을 해줘서 명확히 확인을 하고 싶어서 질문을 드리게 되었습니다.

 

 

A a;
B b;

A& ref = b;
b.getThis()->print();
ref.getThis()->print();

 

해당 내용 관련해서 수업시간에 해주신 내용을 제가 받아적은 내용을 보니,

 

"ref가 A type이라서, B*를 리턴해줘도 그걸 다시 A*로 내부적으로 바꾼 다음 프린트를 호출하는 구조이다." 라고 적었는데...

 

Gemini는 아니라는 답변을 주더라고요.

 

수업시간에 해주신 내용이 맞는건지 다시 한번 문의드리고 싶습니다.

 

그리고 공변반환형이 왜 필요한지? 예제 코드에서 ref.getThis()->print();를 했을 때

B: get this()가 출력되고, 그 이후에 A가 출력되는 것이 무슨 의미가 있는지도 궁금합니다.

 

 

감사합니다.

답변 2

0

안녕하세요? 질문&답변 도우미 durams입니다.

교수님의 설명은 틀리지 않았습니다.

먼저 최신 C++ 표준 draft를 살펴보면 아래와 같습니다. (정식 표준이 아니라 draft긴 하지만, 최근 변경 사항이 없었던 내용입니다)

When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function

N5008, § 11.7.3 , p9

그러니 제시해주신 코드에서 ref.getThis()의 반환값은 A*암시적으로 업캐스팅됩니다. 그렇기 때문에 print()를 호출하면 B::print()가 아닌 A::print()가 호출되는 것이죠.


Covariant Return type이 왜 필요한가?라는 질문에는, 이번 강의의 예제를 다시 볼 필요가 있습니다.

A a;
B b;    // B는 A의 파생 클래스

A& ref = b;
b.getThis()->print();
ref.getThis()->print();

이때 '아무리 B::getThisB*를 반환한다 해도, 어차피 A*로 업캐스팅될 거라면 그냥 반환 타입을 A*로 두는 것하고 아무 차이가 없는 것이 아닌가?' 라고 생각할 수도 있습니다. 하지만 차이가 있습니다.

ref가 아닌 b를 보시면, B 클래스 자체에서 getThis를 호출함으로써 B*가 반환됩니다. 만약 covariant return type을 사용하지 않았다면, b.getThis()B*가 아닌 기반 클래스의 포인터인 A*를 반환합니다. 즉, B에서 본인의 포인터를 얻으려고 함수를 호출했는데 캐스팅을 한 번 더 해야하는 불편함이 생기게 됩니다.

또 covariant return type을 사용하면 코드 자체에 객체가 자신의 포인터 또는 참조를 반환한다는 의미를 확실히 전달할 수도 있겠죠.

0

안녕하세요, 인프런 AI 인턴입니다. 김동현님.

공변 반환형에 대한 질문을 주셨군요. 공변 반환형(covariant return type)은 주로 함수가 파생 클래스의 객체를 반환할 때 사용하는 개념입니다. 파생 클래스에서 오버라이딩된 함수는 기반 클래스의 함수보다 더 구체적인(특정한) 객체를 반환할 수 있습니다.

질문에서 주신 코드와 관련된 설명에서 “ref가 A 타입이라서, B*를 리턴해줘도 그걸 다시 A*로 내부적으로 바꾼다”라고 적으셨는데, 이 설명은 문법적으로는 가능하나 실제로는 다르게 동작할 수 있습니다. C++에서 공변 반환형을 사용할 때, 가리키는 객체의 타입에 따라 관련된 멤버 함수가 호출되며, RTTI(실행 시간 타입 식별) 기능에 의해 적절한 객체가 식별되어 함수가 호출됩니다.

Gemini가 잘못 설명했을 수도 있고, 혼동이 생겼을 수도 있습니다. 의문이 드는 경우, 직접 코드로 컴파일하고 실행해서 결과를 확인하는 것이 가장 좋은 방법입니다.

  • 공변 반환형의 사용 이유:
    • 계층 구조가 있는 클래스들(기반 클래스와 파생 클래스)에서 함수 재정의를 할 때, 보다 구체적인 타입을 반환할 수 있게 도와줍니다.
    • 타입의 불변성을 유지하면서 오버라이딩을 허용합니다.

아래 링크들은 유사한 질문에 대한 기존 답변을 포함하고 있어, 도움이 될 수 있습니다:

  1. 공변 반환형에 대해서 질문 있습니다.
    • 이 게시글에서는 공변 반환형이 포인터나 레퍼런스로 사용 가능한 이유에 대해 다룹니다.

현재 질문하신 내용과 관련있는 다른 답변들도 참고하시면서 공부하시면 이해에 도움이 될 것입니다. 저도 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

김동현님의 프로필 이미지
김동현

작성한 질문수

질문하기