Wenn ich Ihnen sage, dass ich einen Hund habe, können Sie davon ausgehen, dass ich ein Haustier habe.
Wenn ich Ihnen sage, dass ich ein Haustier habe, wissen Sie nicht, ob dieses Tier ein Hund ist, es könnte eine Katze oder vielleicht sogar eine Giraffe sein. Ohne zusätzliche Informationen können Sie nicht sicher annehmen, dass ich einen Hund habe.
In ähnlicher Weise ist ein abgeleitetes Objekt ein Basisklassenobjekt (da es eine Unterklasse ist), sodass ein Basisklassenzeiger darauf verweisen kann. Ein Basisklassenobjekt ist jedoch kein abgeleitetes Klassenobjekt, sodass es keinem abgeleiteten Klassenzeiger zugewiesen werden kann.
(Das Knarren, das Sie jetzt hören werden, ist die Analogie Dehnung)
Angenommen, Sie möchten mir jetzt ein Geschenk für mein Haustier kaufen.
Im ersten Szenario weißt du, dass es ein Hund ist, du kannst mir eine Leine kaufen, jeder ist glücklich.
Im zweiten Szenario habe ich dir nicht gesagt, was mein Haustier ist. Wenn du mir also trotzdem ein Geschenk kaufen willst, musst du Informationen wissen, die ich dir nicht gesagt habe (oder nur raten), du kaufst mir eine Leine, wenn es so ist Es stellte sich heraus, dass ich wirklich einen Hund hatte, über den alle glücklich sind.
Wenn ich jedoch tatsächlich eine Katze hatte, wissen wir jetzt, dass Sie eine schlechte Annahme gemacht haben (Besetzung) und eine unglückliche Katze an der Leine haben (Laufzeitfehler).
Wir haben zwei Objekte.
class A { int a; }; class B : A { int b; };
Ordnen Sie eine Instanz von zu
B
. Wir können damit entweder alsA*
oder alsB*
.Ordnen Sie eine Instanz von zu
A
. Wenn wir es in a umwandeln würdenB*
, sollte dem Mitglied Platz zugewiesen werdenb
?quelle
Äh, weil die Basisklasse keine abgeleitete Klasse ist.
Wenn Sie einen gültigen Zeiger auf einen Typ haben, sagen Sie, dass das Objekt, auf das verwiesen wird, bestimmte Daten an bestimmten Stellen enthält, damit wir sie finden können. Wenn Sie einen Zeiger auf ein abgeleitetes Objekt haben, garantieren Sie, dass das Objekt, auf das verwiesen wird, alle Datenelemente von Derived enthält. Wenn Sie jedoch auf eine Basis verweisen, ist dies tatsächlich nicht der Fall, und Bad Things Happen ™.
Bei Derived werden jedoch garantiert alle Basisdatenelemente an denselben Speicherorten gespeichert. Aus diesem Grund kann ein Zeiger auf Base tatsächlich auf Derived verweisen.
quelle
Weil eine abgeleitete Klasse alles enthält, was in der Basisklasse enthalten ist. Eine Basisklasse enthält jedoch nicht alles, was in der abgeleiteten Klasse enthalten ist.
Es wird nicht empfohlen, eine Basisklasse in eine abgeleitete Klasse umzuwandeln: Was passiert, wenn Sie versuchen, auf Mitglieder zuzugreifen, die nicht Teil der Basisklasse sind?
quelle
Dies gilt, weil ein Tiger ein Tier ist:
Animal * pAnimal = new Tiger();
Dies ist nicht gültig, da es nicht wahr ist, dass das Objekt ein Pfeilgiftfrosch ist.
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
quelle
class Base { public: int a; } class Derived : public Base { public: float b; } Base * pBase = new Base(); pBase->a = 7; // setting the value of a in the base // make a pDerived that points to the SAME DATA as pBase Derived * pDerived = pBase; pDerived->a = 5; // this would be okay, base has a public member 'a' pDerived->b = 0.2f; // error pBase has no data member b and pDerived // points to the SAME DATA as pBase
quelle
Da C ++ eine statisch typisierte Sprache ist und implizite Konvertierungen von Basis zu Ableitung zulässig sind, würde das Typsystem beschädigt. Bjarne Stroustrup wollte keine Laufzeitfehler "Nachricht nicht verstanden".
quelle
p->any_method_name(42, "hello", test);
, und der Compiler würde zur Kompilierungszeit keine Überprüfung durchführen, wenn es eine solche Methode gibt, die drei Parameter akzeptiert, da er nicht wissen würde, dass p auf eine Instanz einer Klasse verweist eines statisch bekannten Typs. Die Überprüfung würde auf die Laufzeit verschoben, die teurer und offensichtlich weniger zuverlässig ist (aber auf der positiven Seite flexibler - Sie benötigen beispielsweise keine Untertypisierung oder Generika).Die kurze Antwort
class A{ public: method1(); }; class B: public A{ public: method2(); }; int main(){ // Case 1 A* ptr_base = new B(); // Here I can call all the methods in A by ptr_base even though it is assigned B ... // ... because B is derived from A and has all the information about methods of A // Case 2 B* ptr_derived = new A(); // this will cause error // Now here ptr_derived is assigned information of A ... // ... So with this information can I call (*ptr_derived).method2(); ?... // ... the answer is No because A does not have information of method2() ...; // ... thus this declaration loses its meaning and hence error. return 0; }
quelle
Weil ein Basisklassenzeiger auf eine Instanz der Basisklasse oder einen beliebigen abgeleiteten Typ verweisen kann. Ein abgeleiteter Zeiger kann nur auf diesen abgeleiteten Typ oder eine Unterklasse davon verweisen.
struct Base {}; struct Derived : Base {}; struct Derived2 : Base {}; Base* p = new Derived(); //Fine, Derived inherits from Base Derived* d = new Base(); //Not fine, Base is not an instance of nor derived from Derived. Derived* d2 = new Derived2(); // Also not fine, Derived2 derives from Base, but is not related to Derived.
Was das Warum betrifft: Im Allgemeinen ist der Basiszeiger allgemeiner als der abgeleitete Zeiger. Als solches weiß es weniger über den geerbten Typ. Einem abgeleiteten Zeiger kann ohne Umwandlung kein Zeiger auf einen Basistyp zugewiesen werden, nur weil er nicht erkennen kann, ob der Basiszeiger vom abgeleiteten Typ oder einem seiner untergeordneten Zeiger ist.
quelle
Wenn Sie einem abgeleiteten Klassenzeiger eine Adresse von einem Basisklassenzeiger zuweisen, können Sie einem abgeleiteten Klassenzeiger möglicherweise ein Basisklassenobjekt zuweisen. Sie laufen Gefahr, auf abgeleitete Klassenmitglieder zuzugreifen, wenn Sie keine abgeleitete Klasse haben. Während abgeleitete Klassenmethoden für eine Basisklasse funktionieren würden, würden sie dies nur tun, wenn die Methode nicht auf abgeleitete Klassenmitgliedsdaten zugreifen würde.
Das ist ein großes Risiko.
Deshalb zwingen wir Sie zum Casting, damit Sie den Haftungsausschluss anerkennen müssen, der besagt (Sie können einen dummen Fehler machen, bitte seien Sie vorsichtig).
quelle
Dies liegt daran, dass "der Typ eines Zeigers der Objekttyp ist, auf den der Zeiger zeigt". Damit,
dann erwarten wir ein Basistypobjekt (und möchten auf seine Funktionen zugreifen) an der Adresse, auf die B zeigt, und wenn wir an dieser Adresse ein abgeleitetes Typobjekt erhalten, können wir auch auf die erforderlichen Funktionen zugreifen. Dies liegt daran, dass der abgeleitete Typ ein Basistyp ist.
dann erwarten wir ein abgeleitetes Typobjekt an der Adresse, auf die D zeigt, und wenn wir dort ein Basistypobjekt erhalten, können wir nicht auf abgeleitete Klasseninformationen vom Basistypobjekt zugreifen, da der Basistyp kein abgeleiteter Typ ist.
quelle
Taten sagen mehr als Worte. Auch das Kind kann ein Elternklassenobjekt haben. Wenn Sie Zeiger gut verstehen, sind die Einschränkungen für Sie nicht gegeben. Im folgenden Code wurden beide Werte mit einem untergeordneten Klassenzeiger (der ein übergeordnetes Klassenobjekt hatte) gedruckt. Auch bewiesen, dass durch Drucken ihrer Adresse. Anregungen sind willkommen!
#include<iostream> using namespace std; class Baap{ public: int a; void hoo(){ cout<<"hoo\n"; cout<<a;} }; class Beta:public Baap{ public: int a; int b; void hee(){ cout<<"hee\n"; } }; int main(){ Baap baap; baap.a=1; Beta *beta=(Beta*)&baap; baap.a=3; beta->hee(); beta->hoo(); cout<<"\n beta = "<<beta<<"\n&baap = "<<&baap; return 0; } //output hee hoo 3 beta = 0x7ffd11dd3834 &baap = 0x7ffd11dd3834
quelle
Im Allgemeinen kann ein Zeiger eines Typs nicht auf ein Objekt eines anderen Typs zeigen. Es gibt jedoch eine wichtige Ausnahme von dieser Regel, die sich nur auf abgeleitete Klassen bezieht.
In dieser Situation kann ein Zeiger vom Typ
BASE*
auf ein Objekt vom Typ zeigenDerived
, dh ein Basisklassenzeiger kann auf ein abgeleitetes Klassenobjekt zeigen, aber umgekehrt ist dies nicht der Fall, da das Basisobjekt nicht das Unterklassenobjekt ist.quelle