Frage zur Vererbung
-
Die öffentliche Vererbung ist eigentlich dafür da, Gemeinsamkeiten von einigen Klassen (mit demselben Einsatzzweck) in einer Basisklasse zusammenzufassen. In erster Linie nicht, weil es Schreibarbeit sparen könnte, sondern weil man bestimmten Code, der sich nicht dafür interessiert, was genau der dynamische Typ eines Objekts ist, für Objekte von irgendwelchen von der Basisklasse abgeleiteten Klasse nutzbar machen kann.
void foo(base* ptr) { cout << ptr->gemeinsamkeit() << endl; } int main() { derived1 d1; derived2 d2; foo(&d1); foo(&d2); }
-
Ich glaube, du interpretierst auch das Disassembly falsch. Da wird gar nichts neu erstellt. Der Wert von var in dem aufrufenden Objekt (hier h) wird überschrieben. Ganz sicher. Siehst du doch, wenn du h.var hinterher ausgibst.
-
Ok mit dem "Variable wird neu erstellt" das war wohl der falsche ausdruck.
void hen :: init () 0040158E /$ 55 PUSH EBP 0040158F |. 89E5 MOV EBP,ESP 00401591 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 00401594 |. C700 2C010000 MOV DWORD PTR DS:[EAX],12C ; 12c = 300 0040159A |. 5D POP EBP 0040159B \. C3 RETNNachdem ich hen::init() ausgeführt habe steht in EAX die Adresse: 00443024
An EAX(00443024) steht auch die 300 (12c hex).Wenn dann meine Funktion void data :: print () augerufen wird ist das hier die Stelle die mich jetzt wundert:
Ein Teil aus der Funktion void data :: print () 00401566 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; EBP+8 = 00443020Würde EBP+8 auf die Adresse 00443024 zeigen dann würde ich mit der Funktion void data :: print () ja auch die 300 ausgeben bekommen.
Ich dachte eigentlich über die Vererbung kann man auf die Variablen einer anderen Klasse zugreifen.
Was mache ich da falsch oder wo ist da der Denkfehler?
-
Ok so kann ich es noch besser Erklären was mich wundert.
void data :: print () { std::cout<<"data::print() " << &var << std::endl; // Gibt aus 0x443020 } void hen :: init () { std::cout<<"hen::init() " << &var << std::endl; // Gibt aus: 0x443024 }Hier habe ich jetzt erwartet das ich zweimal die selbe Adresse herausbekomme.
-
Das was du da heraus bekommst, hängt doch von der Objektinstanz ab, sofern var nicht static ist. Ich glaube, du hast das ganze Grundkonzept von Klassen und Objekten nicht verstanden. Ein Objekt ist die konkrete Instanzierung einer Klasse. Davon kann es ganz viele geben.
-
Dann hab ich hier doch jetzt 2 int Variablen im Speicher stehen oder nicht?
Weil die 8 und die 3 stehen ja jeweils an verschiedenen Stellen im Speicher.#include <iostream> using namespace std; class car { public: int sp; }; car a; car b; int main() { a.sp = 8; cout<<a.sp<<endl; // Gibt 8 aus b.sp = 3; cout<<b.sp<<endl; // Gibt 3 aus system("PAUSE"); return 0; }Ich habe mir hier: http://www.cpp-tutor.de/cpp/le09/klassen.html
auch mal den Teil "Objekte in der Theorie" durchgelesen aber das hilft mir auch nicht weiter.Hat jemand zufällig noch eine bessere Quelle zu dem Thema?
-
Die Grundlagen der Objektorientierung in C++ entnimmst du lieber einem guten Buch. Wenn dir nämlich die Sache mit den Instanzierungen unklar (beziehungsweise seit heute neu) ist, dann hast du es irgendwie geschafft, die Sprachmittel zwar zu kennen, aber nicht richtig verstanden zu haben. Und das ist nicht gut (für dich). Siehe den Link in meiner Signatur für Buchempfehlungen.
-
Nochmal kurz zu der Sache "erstellt im Speicher eine neue Variable".
Das konnte ich im C++ Primer im Bezug zu Objekten finden:
In C++, an object is just a variable, and the purest definition is “a
region of storage” (this is a more specific way of saying, “an object
must have a unique identifier,” which in the case of C++ is a
unique memory address). It’s a place where you can store data, and
it’s implied that there are also operations that can be performed on
this data.Ich habe das so verstanden:
- Jedes Objekt hat eine einzartige Adresse.
- Ein Objekt ist eine bestimmte Region im Speicher.Im Disassembly von IDA Pro sieht das jetzt so aus:
.text:00401168 var_8 = dword ptr -8
.text:00401168 var_4 = dword ptr -4Und das sind doch 2 Variablen die da auf dem Stack angelegt werden ... (Bei Funktionen da konnte ich dieses Verhalten nicht beobachte, die Funktion wurden nicht 2 mal angelegt.)
Bei Funktionen sah es so aus:
lea eax,dword ptr ds:[ebp-4]
push eax
call Adresse ABClea edx,dword ptr ds:[ebp-8]
push edx
call Adresse ABCDas Program funktionierte natürlich selbst wenn man lea und push vor den 2 Funktionsaufrufen entfernt hat.
Ausgabe von IDA Pro:
.text:00401168 ; int __cdecl main(int argc,const char **argv,const char *envp) .text:00401168 _main proc near ; DATA XREF: .data:0040204Co .text:00401168 .text:00401168 var_8 = dword ptr -8 .text:00401168 var_4 = dword ptr -4 .text:00401168 argc = dword ptr 8 .text:00401168 argv = dword ptr 0Ch .text:00401168 envp = dword ptr 10h .text:00401168 .text:00401168 push ebp .text:00401169 mov ebp, esp .text:0040116B add esp, 0FFFFFFF8h .text:0040116E push offset s ; "ok" .text:00401173 push ds:@_STL@cout ; int .text:00401179 call sub_401288 .text:0040117E add esp, 8 .text:00401181 mov [ebp+var_4], 1 .text:00401188 mov [ebp+var_8], 2 .text:0040118F push offset sub_401680 .text:00401194 lea eax, [ebp+var_4] .text:00401197 push eax .text:00401198 push offset aC ; "c: " .text:0040119D push ds:@_STL@cout ; int .text:004011A3 call sub_401288 .text:004011A8 add esp, 8 .text:004011AB push eax .text:004011AC call @$beql$qrx5_GUIDt1 ; operator==(_GUID &,_GUID &) .text:004011B1 add esp, 8 .text:004011B4 push eax .text:004011B5 call sub_401268 .text:004011BA add esp, 8 .text:004011BD push offset sub_401680 .text:004011C2 push [ebp+var_4] .text:004011C5 push offset aC_v ; "c.v: " .text:004011CA push ds:@_STL@cout ; int .text:004011D0 call sub_401288 .text:004011D5 add esp, 8 .text:004011D8 push eax .text:004011D9 call @$beql$qrx5_GUIDt1_0 ; operator==(_GUID &,_GUID &) .text:004011DE add esp, 8 .text:004011E1 push eax .text:004011E2 call sub_401268 .text:004011E7 add esp, 8 .text:004011EA push offset sub_401680 .text:004011EF lea edx, [ebp+var_8] .text:004011F2 push edx .text:004011F3 push offset aB ; "b: " .text:004011F8 push ds:@_STL@cout ; int .text:004011FE call sub_401288 .text:00401203 add esp, 8 .text:00401206 push eax .text:00401207 call @$beql$qrx5_GUIDt1 ; operator==(_GUID &,_GUID &) .text:0040120C add esp, 8 .text:0040120F push eax .text:00401210 call sub_401268 .text:00401215 add esp, 8 .text:00401218 push offset aOk2 ; "ok2" .text:0040121D push ds:@_STL@cout ; int .text:00401223 call sub_401288 .text:00401228 add esp, 8 .text:0040122B mov [ebp+var_4], 8 .text:00401232 push [ebp+var_4] .text:00401235 push ds:@_STL@cout ; _STL::cout .text:0040123B call @$beql$qrx5_GUIDt1_0 ; operator==(_GUID &,_GUID &) .text:00401240 add esp, 8 .text:00401243 push offset command ; "PAUSE" .text:00401248 call _system .text:0040124D pop ecx .text:0040124E xor eax, eax .text:00401250 pop ecx .text:00401251 pop ecx .text:00401252 pop ebp .text:00401253 retn .text:00401253 _main endpDas ganze nochmal in C++
#include <iostream> using namespace std; class var { public: int v; }; int main() { var c; var b; cout<<"ok"; c.v=1; b.v=2; cout<<"c: " << &c<<endl; cout<<"c.v: " << c .v<<endl; cout<<"b: " <<&b<<endl; cout<<"ok2"; c.v=8; cout<<c.v; system("PAUSE"); return 0; }Daher werden meiner Meinung nach durch die Befehle:
c.v=1;
b.v=2;Zwei Variablen auf dem Stack angelegt, obwohl man ja oben in der Klasse nur eine deklariert hat aber man hat ja die zwei Objekte und diese "werden zu" Variable var. (Aber ein Objekt ist ja auch eine Variable).
-
Du hast mit
var c; var b;zwei Variablen auf dem Stack angelegt. Mit
c.v=1; b.v=2;werden diese beiden benutzt.
class var { public: int v; };definiert keine Variable, sondern eine Klasse - deswegen auch "class".
-
srsbsns schrieb:
Nochmal kurz zu der Sache "erstellt im Speicher eine neue Variable".
Vergiss die Diskussion. Solange du nicht den Unterschied zwischen einer Klasse und einen Objekt (Instanz) verstehst, bringt die Diskussion nichts.
Eine Klasse ist nur eine Schablone, sie existiert nicht im Speicher. Ein Objekt ist eine konkrete Instanz die diese Schablone erfüllt.
class Auto { public: Auto( string const & marke) : marke(marke) { } string marke; } int main() { Auto auto1("Audi"), auto2("Ford"); // <-- Jedes Auto hat seinen eigenen Wert für marke }Ob man Vererbung verwendet oder nicht ist dabei völlig egal, eine Instanz hat seine eigenen Variablenwerte.
Wenn man wirklich (was eher selten ist) eine Variable haben will die für alle Instanzen die gleiche ist, muss man diese mit static markieren, dann gibt es wirklich nur eine.
P.S: Wenn man eine Klasse Mensch mit einem Namen hat, erwartet man ja auch nicht das jeder Egon Müller heißt... ;p
-
Ich glaub so langsam komm ich dahinter.

Danke für euere Geduld.