2017-12-28 33 views
2

상속을 통해 두 개의 간단한 클래스를 만들고 하위 클래스에 가상 함수와 재정의를 추가합니다.C++ : 포인터가없는 공변 반환 형식

이 경우
class Parent 
{ 
public: 
    virtual Parent foo(); 
}; 

class Child : public Parent 
{ 
public: 
    Child foo() override; 
}; 

, 내 오버라이드 (override) 함수는 오류가 발생합니다 : error C2555: 'Child::foo': overriding virtual function return type differs and is not covariant from 'Parent::foo'

내가 포인터를 반환 형식을 변경하는 경우 :

class Parent 
{ 
public: 
    virtual Parent* foo(); 
}; 

class Child : public Parent 
{ 
public: 
    Child* foo() override; 
}; 

오류가 사라! 반환 형식의 공분산을 포인터로 수행해야하는 이유와 값 형식이나 참조를 사용할 수없는 이유를 모르겠습니다. 일부 웹 사이트 또는 포럼에서는 반환 값이 함수에 사용 된 값의 복사본이기 때문에 컴파일러에서 포인터의 일정한 크기를 알고 있지만 재정의 된 함수와 부모 함수에 대해 다른 크기를 나타내야한다는 것을 설명합니다. 이는 분명히 불가능합니다 .

그래서이 경우 포인터 이외의 다른 것을 사용할 수없는 이유는 무엇입니까? 포인터를 사용하지 않고 재정의 된 함수에서 자식 형식을 사용하려면 각 함수의 기본 클래스를 반환하고 반환 된 형식을 자식 형식으로 캐스팅해야합니까?

+1

보조 이외 : 포인터를 사용할 필요가 없습니다. 참조도 사용할 수 있습니다. –

+1

"함수는 포인터를 사용하지 않고 각 함수의 기본 클래스를 반환하고 반환 된 형식을 자식 형식으로 캐스팅해야합니다."아니요. 부모 개체를 자식으로 캐스팅 할 수 없습니다. 반환 된 객체는 전체 객체입니다. 자식은 없습니다. 'return child;라고하면'Child' 객체는 * sliced ​​*를 얻고'Parent' 부분 만 복사합니다. –

답변

5

공변 반환 형식의 아이디어가 polymorpihc 반환 유형입니다. 그리고 C++에서는 포인터 나 참조없이 런타임 다형성을 가질 수 없습니다. 대부분의 어려움을 무시하고 가능한 한 가장하자.

o 무엇
void bar(Parent * p) { 
    auto o = p->foo(); 
} 

: 여기 Parent 인터페이스에 의해 일을 처리하는 내 코드는? 음, 물론 Parent입니다. Parent::foo의 리턴 타입에 이렇게 쓰여 있습니다. 그러나 pChild을 가리키고 있다면 어떨까요? 추론 된 유형 o은 여전히 ​​Parent이므로 잘 슬라이스 된 객체를 얻습니다. 다형성 행동이 없으므로 전체 운동은 무의미합니다.

최악의 경우, 그리고 분명히 정의되지 않은 동작이 발생합니다.

그렇기 때문에 공동 변형 반환 유형은 포인터 또는 참조 여야합니다.

0

파생 된 형식이 파생 된 인스턴스를 반환하지만 호출자가 부모를 기다리고 있기 때문에 이것은 포인터를 사용할 때와 다릅니다. 포인터의 경우 파생 포인터가 부모 포인터 용으로 예약 된 공간으로 밀어 넣을 수 있습니다. 실제 인스턴스에 대해 이야기 할 때도 마찬가지입니다. 또한 파생 된 메서드가 파생 된 인스턴스를 반환하지만 부모 포인터를 사용하는 호출자는 이에 대해 모르기 때문에 부모 파트 만 파괴 할 수 있다는 문제가 있습니다.

찾을 수 this 도움이