C ++ 가상 함수 반환 유형 유형으로 가상 함수를 구현할 수 있습니까

상속 된 클래스가 다른 반환 유형으로 가상 함수를 구현할 수 있습니까 (템플릿을 반환으로 사용하지 않음)?



답변

경우에 따라 예, 반환 유형이 원래 반환 유형과 공변 하는 한 파생 클래스가 다른 반환 유형을 사용하여 가상 함수를 재정의하는 것이 합법적입니다 . 예를 들어 다음을 고려하십시오.

class Base {
public:
    virtual ~Base() {}

    virtual Base* clone() const = 0;
};

class Derived: public Base {
public:
    virtual Derived* clone() const {
        return new Derived(*this);
    }
};

여기에서 를 반환하는 Base라는 순수 가상 함수를 정의 clone합니다 Base *. 파생 된 구현에서이 가상 함수는 반환 형식을 사용하여 재정의됩니다 Derived *. 반환 유형은 기본과 동일하지 않지만 언제든지 작성할 수 있기 때문에 완벽하게 안전합니다.

Base* ptr = /* ... */
Base* clone = ptr->clone();

에 대한 호출 clone()은 항상 Base객체에 대한 포인터를 반환합니다.를 반환 Derived*하더라도이 포인터는 암시 적으로 a로 변환 가능 Base*하고 작업이 잘 정의되어 있기 때문입니다.

보다 일반적으로 함수의 반환 유형은 서명의 일부로 간주되지 않습니다. 반환 유형이 공변이면 모든 반환 유형으로 멤버 함수를 재정의 할 수 있습니다.


답변

예. 반환 유형은 공변 인 한 다를 수 있습니다 . C ++ 표준은이를 다음과 같이 설명합니다 (§10.3 / 5).

재정의 함수의 반환 유형은 재정의 된 함수의 반환 유형과 동일하거나 함수 클래스와 공변 해야합니다. 함수가 함수를 D::f재정의하는 B::f경우 다음 기준을 충족하면 함수의 반환 유형이 공변합니다.

  • 둘 다 클래스에 대한 포인터 또는 클래스 98에 대한 참조 )
  • 의 반환 유형에 B::f있는 클래스는 D::f또는 의 반환 유형에있는 클래스와 동일한 클래스이고,의 반환 유형에있는 클래스 의 명확한 직접 또는 간접 기본 클래스이고에서 D::f액세스 할 수 있습니다.D
  • 포인터 또는 참조는 모두 동일한 cv-qualification을 D::f가지며의 반환 유형에있는 클래스 유형은의 반환 유형에있는 클래스 유형과 같거나 cv-qualification이 적거나 cv-qualification이 적습니다 B::f.

각주 98은 “클래스에 대한 다중 레벨 포인터 또는 클래스에 대한 다중 레벨 포인터에 대한 참조는 허용되지 않습니다.”라고 지적합니다.

요컨대, if D가의 하위 B유형 인 경우 함수 D의 반환 유형은에서 함수의 반환 유형의 하위 유형이어야합니다 B. 반환 유형에 따라 자신을 때 가장 일반적인 예는 D하고 B있지만 될 필요가 없습니다. 두 개의 개별 유형 계층이있는 경우를 고려하십시오.

struct Base { /* ... */ };
struct Derived: public Base { /* ... */ };

struct B {
  virtual Base* func() { return new Base; }
  virtual ~B() { }
};
struct D: public B {
  Derived* func() { return new Derived; }
};

int main() {
  B* b = new D;
  Base* base = b->func();
  delete base;
  delete b;
}

이것이 작동하는 이유는 호출자 funcBase포인터를 기대 하기 때문 입니다. 모든 Base포인터가 작동합니다. 따라서 D::func항상 Derived포인터를 반환하겠다고 약속하면 모든 Derived포인터가 암시 적으로 Base포인터 로 변환 될 수 있기 때문에 항상 조상 클래스가 배치 한 계약을 충족합니다 . 따라서 발신자는 항상 기대하는 것을 얻을 수 있습니다.


반환 유형을 변경하는 것 외에도 일부 언어에서는 재정의 함수 의 매개 변수 유형 도 변경할 수 있습니다. 그렇게 할 때 일반적으로 반 변성이 필요합니다 . 경우 즉, B::f을 받아 Derived*, 다음 D::fa를 허용 할 것이다 Base*. 후손들은 그들이 받아들이는 것에 대해 더 느슨해 지고 그들이 반환하는 것에 더 엄격 해질 수 있습니다 . C ++에서는 매개 변수 유형 반공 변성을 허용하지 않습니다. 매개 변수 유형을 변경하면 C ++는이를 새로운 함수로 간주하므로 오버로딩 및 숨기기가 시작됩니다. 이 주제에 대한 자세한 내용 은 Wikipedia의 공분산 및 반공 분산 (컴퓨터 과학) 을 참조하십시오 .


답변

가상 함수의 파생 클래스 구현은 공변 반환 유형을 가질 수 있습니다 .


답변