수색…
비고
가상 멤버 함수 m
에 대한 매개 변수 또는 반환 값의 공분산 은 유형 T
가 파생 클래스의 m
재정의에서보다 구체적으로되는 곳입니다. 그런 다음 유형 T
는 m
제공하는 클래스와 동일한 방식 ( 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