수색…


비고

가상 멤버 함수 m 에 대한 매개 변수 또는 반환 값의 공분산 은 유형 T 가 파생 클래스의 m 재정의에서보다 구체적으로되는 곳입니다. 그런 다음 유형 Tm 제공하는 클래스와 동일한 방식 ( co )으로 특이성이 다양합니다 ( 분산 ). C ++은 원시 포인터 또는 원시 참조 인 공변 리턴 유형에 대한 언어 지원을 제공합니다. 공분산은 pointee 또는 referent 유형입니다.

C ++에서는 함수 반환 값이 C ++의 유일한 순수 출력 인수 이기 때문에 C ++ 지원은 반환 유형으로 제한되며 공분산은 순수한 out 인수 에 대해서만 유형 안전합니다. 그렇지 않으면 호출 코드는 수신 코드가 예상하는 것보다 덜 구체적인 유형의 객체를 제공 할 수 있습니다. MIT의 Barbara Liskov 교수는이 문제와 관련 분산 유형 안전 문제를 조사했으며 현재 Liskov Substitution Principle 또는 LSP 로 알려져 있습니다.

공분산 지원은 본질적으로 다운 캐스팅 및 동적 유형 검사를 피하는 데 도움이됩니다.

스마트 포인터는 클래스 포인터 타입이기 때문에 스마트 포인터 결과에 대해 직접적으로 공분산에 대한 내장 된 지원을 사용할 수는 없지만 원시 포인터를 생성하는 공변량 virtual 함수에 대한 공분산virtual 스마트 포인터 결과 래퍼 함수를 ​​정의 할 수 있습니다.

1. 공변 수익률이없는 기본 사례는 왜 그들이 바람직한지를 보여줍니다.

// 1. Base example not using language support for covariance, dynamic type checking.

class Top
{
public:
    virtual Top* clone() const = 0;
    virtual ~Top() = default;       // Necessary for `delete` via Top*.
};

class D : public Top
{

public:
    Top* clone() const override
    { return new D( *this ); }
};

class DD : public D
{
private:
    int answer_ = 42;

public:
    int answer() const
    { return answer_;}

    Top* clone() const override
    { return new DD( *this ); }
};

#include <assert.h>
#include <iostream>
#include <typeinfo>
using namespace std;

int main()
{
    cout << boolalpha;

    DD* p1 = new DD();
    Top* p2 = p1->clone();
    bool const  correct_dynamic_type = (typeid( *p2 ) == typeid( DD ));
    cout << correct_dynamic_type << endl;               // "true"

    assert( correct_dynamic_type ); // This is essentially dynamic type checking. :(
    auto p2_most_derived = static_cast<DD*>( p2 );
    cout << p2_most_derived->answer() << endl;          // "42"
    delete p2;
    delete p1;
}

2. 기본 예제, 정적 유형 검사의 공변 결과 버전.

// 2. Covariant result version of the base example, static type checking.

class Top
{
public:
    virtual Top* clone() const = 0;
    virtual ~Top() = default;       // Necessary for `delete` via Top*.
};

class D : public Top
{
public:
    D* /* ← Covariant return */ clone() const override
    { return new D( *this ); }
};

class DD : public D
{
private:
    int answer_ = 42;

public:
    int answer() const
    { return answer_;}

    DD* /* ← Covariant return */ clone() const override
    { return new DD( *this ); }
};

#include <iostream>
using namespace std;

int main()
{
    DD* p1 = new DD();
    DD* p2 = p1->clone();
    // Correct dynamic type DD for *p2 is guaranteed by the static type checking.

    cout << p2->answer() << endl;          // "42"
    delete p2;
    delete p1;
}

3. 공변량 스마트 포인터 결과 (자동 정리).

// 3. Covariant smart pointer result (automated cleanup).

#include <memory>
using std::unique_ptr;

template< class Type >
auto up( Type* p ) { return unique_ptr<Type>( p ); }

class Top
{
private:
    virtual Top* virtual_clone() const = 0;

public:
    unique_ptr<Top> clone() const
    { return up( virtual_clone() ); }

    virtual ~Top() = default;       // Necessary for `delete` via Top*.
};

class D : public Top
{
private:
    D* /* ← Covariant return */ virtual_clone() const override
    { return new D( *this ); }

public:
    unique_ptr<D> /* ← Apparent covariant return */ clone() const
    { return up( virtual_clone() ); }
};

class DD : public D
{
private:
    int answer_ = 42;

    DD* /* ← Covariant return */ virtual_clone() const override
    { return new DD( *this ); }

public:
    int answer() const
    { return answer_;}

    unique_ptr<DD> /* ← Apparent covariant return */ clone() const
    { return up( virtual_clone() ); }
};

#include <iostream>
using namespace std;

int main()
{
    auto  p1 = unique_ptr<DD>(new DD());
    auto  p2 = p1->clone();
    // Correct dynamic type DD for *p2 is guaranteed by the static type checking.

    cout << p2->answer() << endl;          // "42"
    // Cleanup is automated via unique_ptr.
 }


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow