C ++: Wie kann ich „ungültig kovarianten Rückgabetyp“ in geerbten Klassen ohne Gießen vermeiden?

StackOverflow https://stackoverflow.com/questions/2410532

  •  18-09-2019
  •  | 
  •  

Frage

Ich habe eine ziemlich komplexe Klassenhierarchie, in dem die Klassen sind kreuzartig aufeinander abhängig: Es gibt zwei abstrakte Klassen A und C enthält, ein Verfahren, das eine Instanz von C und A zurückkehrt, respectively. In ihren geerbten Klassen mag ich einen Co-Variant-Typen verwenden, die in diesem Fall ein Problem, da ich die Vererbungsbeziehung Schiff keine Art und Weise kennen zu zukunfts zu erklären.

I erhalten eine "test.cpp: 22: Fehler: ungültige kovarianten Rückgabetyp für 'virtuelle D * B :: OUTC ()'" - Fehler, da der Compiler nicht weiß, dass D eine Unterklasse von C

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Wenn ich den Rückgabetyp von B :: OUTC () bis C ändern * das Beispiel kompiliert. Gibt es eine Möglichkeit B * und D * als Rückgabetypen in den vererbten Klassen zu halten (es wäre mir intuitiv sein, dass es eine Art und Weise)?

War es hilfreich?

Lösung

Ich kenne keine Art und Weise direkt gekoppelt in C covariant Mitglieder haben ++. Sie werden entweder eine Schicht hinzuzufügen haben oder implementieren kovarianter selbst zurück.

Für die erste Option

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class BI : public A {
public:
};

class D : public C {
public:
        BI* outA();
};

class B: public BI {
public:
        D* outC();
};

D* B::outC() {
        return new D();
}

BI* D::outA() {
        return new B();
}

und für das zweite

class C;

class A {
public:
        C* outC() { return do_outC(); }
        virtual C* do_outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
        virtual C* do_outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return static_cast<D*>(do_outC());
}

C* B::do_outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Beachten Sie, dass diese zweite Option ist, was implizit vom Compiler durchgeführt wird (mit einigen statischen Kontrollen, dass die static_cast gültig ist).

Andere Tipps

Soweit ich weiß, gibt es keine Möglichkeit, dies ohne explizites Casting zu tun. Das Problem ist, dass die Definition der Klasse B kann nicht wissen, dass D eine Unterklasse von C ist, bis es eine vollständige Definition der Klasse D sieht, aber die Definition der Klasse D nicht, dass B weiß, ist eine Unterklasse von A, bis er sieht eine vollständige Definition der Klasse B, und so haben Sie eine zirkuläre Abhängigkeit. Dies kann nicht mit zukunfts Erklärungen gelöst werden, da eine Vorwärtsdeklaration leider nicht eine Vererbungsbeziehung angeben.

Es gibt ein ähnliches Problem mit dem Versuch, eine kovariante clone() Methode mit Hilfe von Vorlagen zu implementieren, , die ich finden kann gelöst werden, aber die analoge Lösung immer noch nicht hier, weil die kreisförmige Referenz bleibt unmöglich zu lösen.

Sie können dies nicht aufgrund Clientseite Erwartung. Wenn eine C-Instanz verwenden, können Sie nicht sagen, welche Art von C ist es (ein D oder etwas anderes). Wenn Sie also den B-Zeiger speichern (von einem Aufruf der abgeleiteten Klasse resultierenden, aber Sie wissen es nicht bei der Kompilierung) in einen Ein Zeiger, ich bin nicht sicher, dass der gesamte Speicher Sachen richtig sein wird.

Wenn Sie eine Methode auf einem polymorphen Typ nennen, hat die Laufzeitumgebung die dynamische Art des Objekts zu überprüfen, und es bewegt sich Zeiger auf Ihre Klassenhierarchie entsprechen. Ich bin nicht sicher, dass Sie auf Kovarianz verlassen sollten. Hier finden Sie aktuelle this

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top