Buscar..


Observaciones

La covarianza de un parámetro o un valor de retorno para una función miembro virtual m es donde su tipo T vuelve más específico en el reemplazo de m de una clase derivada. El tipo T luego varía ( varianza ) en especificidad de la misma manera ( co ) que las clases que proporcionan m . C ++ proporciona soporte de lenguaje para los tipos de retorno covariantes que son punteros en bruto o referencias en bruto, la covarianza es para el tipo de pointee o referente.

El soporte de C ++ está limitado a los tipos devueltos porque los valores de retorno de la función son los únicos argumentos de salida puros en C ++, y la covarianza solo es segura para un argumento de salida puro. De lo contrario, el código de llamada podría proporcionar un objeto de un tipo menos específico del que espera el código de recepción. La profesora del MIT Barbara Liskov investigó esto y relacionó los problemas de seguridad de tipo de varianza, y ahora se conoce como el Principio de Sustitución de Liskov, o LSP .

El soporte de covarianza esencialmente ayuda a evitar la reducción de emisiones y la comprobación dinámica de tipos.

Dado que los punteros inteligentes son del tipo de clase, no se puede usar el soporte integrado para la covarianza directamente para los resultados del puntero inteligente, pero se pueden definir funciones de envoltura de resultados del puntero inteligente no virtual aparentemente covariantes para una función virtual covariante que produce punteros en bruto.

1. Ejemplo de base sin devoluciones covariantes, muestra por qué son deseables

// 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. Versión de resultado covariante del ejemplo base, comprobación de tipos estática.

// 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. Resultado del puntero inteligente covariante (limpieza automatizada).

// 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow