C++
Retourtype Covariantie
Zoeken…
Opmerkingen
Covariantie van een parameter of een retourwaarde voor een virtuele lidfunctie m
is waar het type T
specifieker wordt in een afgeleide klasse 'overschrijving van m
. Het type T
varieert dan ( variantie ) in specificiteit op dezelfde manier ( co ) als de klassen die m
leveren. C ++ taal biedt ondersteuning voor covariante types rendement dat ruwe pointers of ruwe verwijzingen - de covariantie voor pointee of referent type.
De C ++ -ondersteuning is beperkt tot retourtypes omdat functieretourwaarden de enige pure out-argumenten zijn in C ++ en covariantie alleen het type veilig is voor een puur out-argument. Anders zou de aanroepcode een object van een minder specifiek type kunnen leveren dan de ontvangende code verwacht. MIT-professor Barbara Liskov heeft dit en gerelateerde veiligheidsproblemen van het variantie-type onderzocht, en het staat nu bekend als het Liskov Substitution Principle of LSP .
De covariantieondersteuning helpt in wezen om downcasting en dynamische typecontrole te voorkomen.
Aangezien slimme aanwijzers van het klasse type zijn, kan men de ingebouwde ondersteuning voor covariantie niet direct gebruiken voor slimme aanwijzerresultaten, maar men kan ogenschijnlijk covariante niet- virtual
slimme aanwijzer resultaatwikkelfuncties definiëren voor een covariante virtual
functie die onbewerkte wijzers produceert.
1. Basisvoorbeeld zonder covariante retouren, laat zien waarom ze wenselijk zijn
// 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 resultaatversie van het basisvoorbeeld, controle van het statische type.
// 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-resultaat (automatisch opschonen).
// 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.
}