Поиск…


замечания

Ковариация параметра или возвращаемого значения для виртуальной функции-члена m , где его тип T становится более специфичным в переопределении производного класса m . Тип T затем изменяется ( дисперсия ) по специфичности таким же образом ( co ), что и классы, обеспечивающие m . C ++ обеспечивает языковую поддержку для ковариантных типов возвращаемых данных, которые являются необработанными указателями или исходными ссылками - ковариация предназначена для типа адресата или референта.

Поддержка C ++ ограничена возвращаемыми типами, потому что возвращаемые значения функции являются единственными чистыми out-arguments в C ++, а ковариация - только тип safe для чистого аргумента. В противном случае вызывающий код может предоставить объект менее определенного типа, чем ожидает код приема. Профессор Массачусетского технологического института Барбара Лисков изучила эту проблему и связала ее с вопросами безопасности, и теперь она известна как Принцип замещения Лискова или 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