2017-12-01 1 views
0

Ich bin ein bisschen mit so schrecklichen Problem der schlechten Klassenhierarchie fest.Upcasting nicht auf echte Basisklasse

class A {...}; // abstract 
class B : public A {...}; // abstract 
class C {...}; // abstract 

class a1 : public B, public C {...}; // indirect inheritance of A 
class c1 : public A, public C {...}; 

Die Frage: ist es möglich, einen Zeiger (Referenz) auf C in dem Zeiger (Verweis) zur Klasse A. konvertieren

Ich verstehe, dass beste Lösung nur Klasse C von A zu machen ist, geerbt, aber Trotzdem kann es Probleme mit der Klasse a1 (zwei Basen A) geben.

+0

C und A sind völlig unabhängig, also nein, man kann nicht zwischen dem 2 mit einem statischen Guss konvertieren.Möglicherweise können Sie einen Konvertierungsoperator für sie erstellen (oder Sie könnten einfach nur neu entwerfen). – UKMonkey

Antwort

3

die Frage: Ist es möglich, einen Zeiger (Referenz) bis C in den Zeiger (Referenz) zur Klasse A.

nicht konvertiert, es sei denn die Klassen polymorph sind d.h. mindestens eine Funktion virtuellen Element aufweisen. In diesem Fall kann dynamic_cast für die Nebenbesetzung verwendet werden, wie in StoryTellers Antwort gezeigt.

Wenn jedoch dieser Zeiger (Referenz) C auf ein Kind verweist, das A erbt, können Sie zuerst auf diesen untergeordneten Zeiger und dann auf A verweisen.

c1 c; 
C& cref = c; 
A& aref = static_cast<c1&>(cref); 

Das ist natürlich nicht unbedingt ideal, weil Sie nicht nur jeden beliebigen C Zeiger, dessen Betontypen ist unbekannt umwandeln können.

Ich verstehe, dass beste Lösung von A nur Klasse C

zu machen ist, geerbt Wenn Sie dies getan hat, dann werden alle C Zeiger würde A Zeiger implizit konvertierbar sein.

aber immer noch kann es einige Probleme mit der Klasse a1 (zwei Basis A) verursachen.

Um die Probleme zu umgehen, benötigen Sie gemeinsame Basen, z. B. virtuelle Vererbung.

struct A {}; // abstract 
struct B : virtual A {}; // abstract 
struct C : virtual A {}; // abstract 

struct a1 : B, C {}; // indirect inheritance of A 
struct c1 : C {}; 

int main() { 
    c1 c; 
    C& cref = c; 
    A& aref = cref; 
} 
3

Was Sie versuchen, wird als "Side-Cast" bezeichnet. Und der eingebaute Ausdruck dynamic_cast kann das tun. Aber es ist nicht billig, und Sie haben RTTI in Ihrem Projekt besser nicht abgeschaltet (Sie haben bereits erwähnt, dass Ihre Klassen abstrakt sind, was virtuelle Funktionen mit sich bringt, deren Deklarationen für RTTI benötigt werden).

anzeigen Live

#include <cassert> 

struct A { 
    virtual ~A() = default; 
}; 

struct B : public A { 
    virtual ~B() = default; 
}; 

struct C { 
    virtual ~C() = default; 
}; 

struct a1 : public B, public C { 
    a1() = default; 
    virtual ~a1() = default; 

}; // indirect inheritance of A 

int main() { 
    a1 a; 

    C* c = &a; 

    assert(dynamic_cast<A*>(c) != nullptr); 

    return 0; 
} 

Aber Ihre Gefühle über das Müssen Ihre Klassen sind meiner Meinung nach sehr gerechtfertigt neu zu entwerfen. Die Notwendigkeit einer Nebenbesetzung sollte nicht auftreten.

+0

Ich würde ausdrücklich erwähnen, dass das Hinzufügen einer virtuellen Memberfunktion erforderlich ist, um dynamic_cast zuzulassen. – user2079303

+0

@ user2079303 - Danke, machte die Annahme explizit. Ich ging vom OP weg und sagte, dass diese Klassen abstrakt sind. – StoryTeller

0

Beide obigen Antworten sind richtig, aber die erste ist weiter erklärt, denke ich. Eine andere Lösung, die ich möglicherweise einen seltsamen Besucher schafft wird verwenden, wie:

PointerCreator 
{ 
    void visit (const a1 & _a) 
    { 
    m_pointerToA = &_a; 
    } 

    void visit (const c1 & _c) 
    { 
    m_pointerToA = &_a; 
    } 

    A * m_pointerToA; 
}; 

PointerCreator pC; 
a1.accept(pC); 
A& = *pC.m_pointerToA; 
+0

Nun, vielleicht könnte es irgendwann nützlich sein ... aber ich würde es nicht als den üblichen Weg betrachten, es zu tun. Und wenn Sie einen Besucher verwenden, möchten Sie vielleicht den Besucher eine bestimmte Aktion ausführen, da er in der Lage wäre, Fälle zu bearbeiten, in denen kein Ziel oder mehrere Ziele vorhanden sind. – Phil1970