I 2 Ausgaben im Code sehen:
- Da Ihre Klassen sind verantwortlich für die Speicherverwaltung, würde ich vorschlagen, Ihre Destruktoren
virtual
zu machen, denn wenn man an einem beliebigen Punkt, versucht abgeleitet löschen Klassenobjekt über Basiszeiger, werden die Destruktoren abgeleiteter Klassen nicht aufgerufen. Es sollte kein Problem in Ihrem aktuellen Code sein, aber kann ein Problem in einer Zukunft werden.
D.h.:
int main()
{
AA* aa = new BB (2);
delete aa;
}
Wird nicht die BB::~BB()
in Ihrem Fall nennen.
- Das Problem, das Sie bemerken, und das Schreiben dieser Frage über.
Nachdem Sie Ihre Variable vom Typ BB*
-AA*
werfen (auch wenn die Besetzung nicht notwendig ist, können Sie straight-up zuweisen, aufgrund Arten covariant ist) in Zeile:
AA* cc = dynamic_cast<AA*>(bb);
Ihre Variable cc
wird behandelt, als ob sie vom Typ AA*
ist (es spielt keine Rolle, dass sie den Laufzeittyp BB*
hat, im Allgemeinen - Sie wissen nicht und sollten sich nicht um den genauen Laufzeittyp kümmern). Bei jedem Aufruf virtueller Methoden werden sie über den vtable an den richtigen Typ gesendet.
Und jetzt, warum erhalten Sie seltsame Werte in der Konsole/Segmentierung Fehler gedruckt? Was ist das Ergebnis von cc->getA()
? Da die Variable cc
als AA*
behandelt wird, lautet der Rückgabewert A*
(wie oben erklärt, ist der tatsächliche Typ B*
, aber aufgrund von - wird eine Vererbungsbeziehung wie A*
behandelt). Was ist das Problem, können Sie fragen: Das Array m_a
ist in beiden Fällen die gleiche Größe, oder?
Nun, nicht wirklich, um das zu erklären, ich müsste erklären, wie Array-Indizierung in C++ funktioniert, und wie es mit den Größen der Objekte zusammenhängt.
Ich denke, dass ich Sie nicht schockieren würde, dass die Größe des Objekts vom Typ Angabe B
(sizeof (B)
), ist größer als der Typ A
(sizeof (A)
), da B
hat alles, was A
(durch Vererbung) hat mit einigen eigenen Sachen. Auf meinem Rechner sizeof(A)
= 16 Bytes und sizeof(B)
= 28 Bytes.
Wenn Sie also ein Array erstellen, ist der gesamte Speicherplatz, den das Array belegt, [element_count] * [size of the element]
Bytes, was logisch erscheint. Aber wenn Sie ein Element aus einem Array nehmen müssen, muss es genau bestimmen, wo dieses Element im Speicher ist, in all dem Raum, den das Array belegt, und zwar durch Berechnung. Es geschieht so: [start of the array] + [index] * [size of element]
.
Und jetzt kommen wir an der Quelle des Problems. Sie versuchen cc->getA()[1]
zu tun, aber, da cc
, unter der Haube, ist BB*
, so dass die Größe des AA::m_a
Variable ist 2 * sizeof (B)
(= 2 * 28 = 56
auf meiner Maschine, erste Objekte beginnen bei Offset 0
(0 * sizeof (B)
; Sekunde bei 28
Offset (1 * sizeof(B)
)) , aber seit cc->getA()
wird behandelt als A*, and you are trying to fetch second element from the array (index 1), it tries to fetch the object from the offset of
1 * sizeof (A) `, die leider in der Mitte des reservierten Speicherplatzes für ein Objekt ist, und dennoch können beliebige Werte gedruckt werden/alles kann passieren - undefiniertes Verhalten wird aufgerufen.
Wie es zu beheben?Ich würde es beheben, indem die virtuellen Indizierung Betreiber Umsetzung statt GetA
Methode auf Klassen AA
/BB
wie folgt:
class AA
{
public:
...
virtual A& operator[] (int idx)
{
return m_a[idx];
}
...
};
class BB : public AA
{
public:
...
virtual B& operator[] (int idx)
{
return dynamic_cast<B*>(m_a)[idx];
}
...
};
Aber dann würden Sie vorsichtig sein müssen sich die Betreiber auf dem Objekt aufzurufen, und nicht auf einen Zeiger auf Objekt:
std::cout << cc->operator[](1).idx[0] << "\n";
std::cout << cc->operator[](1).idx[1] << "\n";
std::cout << cc->operator[](1).idx[2] << "\n";
ich schlage vor, lesen Sie den C++ zu FAQ-Bereich [Ist ein Array von einer Art-of-Array of Base Abgeleitet] (https://isocpp.org/wiki/faq/proper -inheritance # array-derived-vs-base). – jotik
Dies könnte als [Array Decay Bug] (http://stackoverflow.com/a/37052920/3919155) bezeichnet werden. – jotik