Kovarianz und Kontravarianz



  • Hallo zusammen
    Ich beschäftige mich gerade mit der Typentheorie : http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) und habe hierzu eine Frage:

    Ich verstehe zwar was Kontravarianz bedeutet, aber ich habe Mühe dies in den Kontext der folgenden Aussage zu bringen:

    The problem for instances of B is how to be perfectly substitutable for instances of A.

    B is abgeleitet von A. Also ich kann mir beim besten Willen nich vorstellen, wie Instancen vom Typ A und B austaschbar sein können, wenn eine Methode vom Typ B einen generelleren Typ akzeptiert als A 😮

    Bspw:

    class P1{
     };
    
     class P2:P1{
     };
    
     class C1{
      public virtual void DoSomething(P2 p2);
     };
    
     class C2{
      public void DoSomething(P1 p1);
     };
    
    C1 *c1 = new C1();
    C2 *c2 = new C2();
    P1 *p1 = new P1();
    c1->DoSomething(p1);
    c2->DoSomething(p1);
    

    Das gibt doch einen Kompilerfehler??? Aber genau dies ist doch "Kontravarianz"?
    Oder bringe ich da etwas durcheinander?

    Mfg Samuel



  • Ishildur schrieb:

    The problem for instances of B is how to be perfectly substitutable for instances of A.

    B is abgeleitet von A. Also ich kann mir beim besten Willen nich vorstellen, wie Instancen vom Typ A und B austaschbar sein können

    Vorsicht bei der Formulierung: die Austauschbarkeit ist nur in einer Richtung gefordert (B muß A substituieren können).

    Ishildur schrieb:

    wenn eine Methode vom Typ B einen generelleren Typ akzeptiert als A 😮

    Wenn B.f() C und A.f() C' erwartet, dann ist der Aufruf von B.f() mit C' legitim, demnach A durch B ersetzbar.

    Ishildur schrieb:

    Das gibt doch einen Kompilerfehler???

    Wenn du all die Kleinigkeiten beseitigst, solltest du mit einer Warnung (C2::DoSomething() verdeckt C1::DoSomething()) davonkommen, aber semantisch funktioniert es trotzdem nicht, weil C++ Kontravarianz für Methodenargumente nicht direkt unterstützt. Der naheliegende Workaround wäre etwa folgendes:

    struct P1 {};
    struct P2 : P1 {};
    
    struct C1
    {
        virtual void f (P2*);
    };
    
    struct C2 : C1
    {
        virtual void f (P2* p) { f (static_cast <P1*> (p)); }
        virtual void f (P1*);
    };
    

Anmelden zum Antworten