Ricerca…


Osservazioni

La covarianza di un parametro o un valore di ritorno per una funzione membro virtuale m è dove il suo tipo T diventa più specifico in un override della classe derivata di m . Il tipo T poi varia ( varianza ) in specificità allo stesso modo ( co ) delle classi che forniscono m . C ++ fornisce supporto linguistico per i tipi di ritorno covarianti che sono puntatori grezzi o riferimenti grezzi - la covarianza è per il tipo punta o referente.

Il supporto C ++ è limitato ai tipi restituiti perché i valori restituiti dalla funzione sono gli unici argomenti out-out in C ++ e la covarianza è solo sicura per un puro argomento out. Altrimenti, il codice chiamante potrebbe fornire un oggetto di tipo meno specifico di quanto previsto dal codice ricevente. La professoressa Barbara Liskov del MIT ha studiato questo problema correlato alla sicurezza della varianza, ed è ora noto come Principio di sostituzione di Liskov, o LSP .

Il supporto della covarianza aiuta essenzialmente ad evitare downcast e controllo dinamico dei tipi.

Poiché puntatori intelligenti sono di tipo classe non si può usare il supporto integrato per covarianza direttamente risultati di puntatore intelligente, ma si può definire apparentemente covariante non virtual funzioni risultato puntatore involucro intelligenti per una covariante virtual funzione che produce i puntatori prime.

1. Esempio di base senza rendimenti covarianti, mostra perché sono desiderabili

// 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. Versione di risultato covariant dell'esempio di base, controllo di tipo statico.

// 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. Risultato puntatore intelligente covariant (pulizia automatica).

// 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow