Suche…


Bemerkungen

Bei der Kovarianz eines Parameters oder eines Rückgabewerts für eine virtuelle Elementfunktion m wird der Typ T in einer abgeleiteten Klasse von m überschrieben. Der Typ T variiert dann ( Varianz ) in der Spezifität auf dieselbe Weise ( co ) wie die Klassen, die m bereitstellen. C ++ bietet Sprachunterstützung für kovariante Rückgabetypen, bei denen es sich um Rohzeiger oder Rohreferenzen handelt. Die Kovarianz bezieht sich auf den Pointee- oder Referenztyp.

Die C ++ - Unterstützung ist auf Rückgabetypen beschränkt, da Funktionsrückgabewerte die einzigen reinen Out-Argumente in C ++ sind und Kovarianz nur für ein reines Out-Argument typsicher ist. Andernfalls könnte der aufrufende Code ein Objekt eines weniger spezifischen Typs liefern, als der empfangende Code erwartet. Die MIT-Professorin Barbara Liskov untersuchte diese und verwandte Sicherheitsprobleme des Typs "Abweichungstyp" und ist jetzt als Liskov-Substitutionsprinzip ( LSP) bekannt .

Die Kovarianz-Unterstützung hilft im Wesentlichen, Downcasting und dynamische Typüberprüfung zu vermeiden.

Da Smart-Pointer vom Klassentyp sind, kann die integrierte Unterstützung für Kovarianz nicht direkt für Smart-Pointer-Ergebnisse verwendet werden. Man kann jedoch scheinbar kovariante nicht- virtual Smart-Pointer-Wrapper-Funktionen für eine kovariante virtual Funktion definieren, die rohe Pointer erzeugt.

1. Basisbeispiel ohne kovariante Renditen zeigt, warum sie wünschenswert sind

// 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. Covariante Ergebnisversion des Basisbeispiels, statische Typüberprüfung.

// 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. Covariant Smart Pointer-Ergebnis (automatisierte Bereinigung).

// 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow