Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Early binding (frühe Bindung) late binding (späte Bindung)

Ähnliche Präsentationen


Präsentation zum Thema: "Early binding (frühe Bindung) late binding (späte Bindung)"—  Präsentation transkript:

1 early binding (frühe Bindung) late binding (späte Bindung)

2 Ausgangspunkt sind wieder die Klassen der letzten Präsentation:

3 #include "stdafx.h" #include using namespace std; class A{ public: A(int i); void hallo(); int x; }; class B: public A{ public: B(int i); void hallo(); int x; int y; };

4 A::A(int i){ x = i; }; void A::hallo(){ cout << "Ich bin A" << "x=" << x << endl; }; B::B(int i):A(i-2){ x = i-1; y = i; }; void B::hallo(){ cout << "Ich bin B" << "x=" << x << "y=" << y << endl; };

5 Welcher Wert welcher Speicherzelle wird durch die gleich folgenden Anweisungen links verändert ? Auf welches Objekt (a oder b) zeigt ap ? if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap; Vom Zufall abhängig, zeigt ap entweder auf das Objekt a oder auf das Objekt b. Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap 0300?

6 Angenommen, ap zeigt auf b. Welchen Wert hat dann ap ? Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap 0300? if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

7 Angenommen, ap zeigt auf b. Welchen Wert hat dann ap ? Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap 0300 if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

8 Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

9 Auf welches x würde dann die Anweisung ap->x = 13 zugreifen ? Es gibt 2 Möglichkeiten: b.A::x oder b.B::x Da sich der Compiler schon beim Compilieren (und nicht erst während der Laufzeit) entscheiden muss, kann es nicht... Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

10 .... B::x sein, da diese Komponente (falls ap auf a zeigt) nicht existiert. Dagegen existiert (egal ob ap auf a oder b zeigt) immer die Komponente A::x. Diesen Vorgang des Compilers nennt man early binding (frühe Bindung). dieses x existiert in a und b Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

11 Also wird der Wert von x im Objekt b verändert auf: Adr a 0100x10 Adr b 0200A::x18 x19 y20 Adr ap if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

12 Adr a 0100x10 Adr b 0200A::x x19 y20 Adr ap if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

13 Adr b 0200A::x13 x19 y20 Also: Der Typ der Zeigervariablen, hier also A, und nicht der Typ des Objekts auf den ap während der Laufzeit zeigt, hier also B, bestimmt welches Mitglied (Member) von *ap angesprochen wird. Adr ap Adr a 0100x10 if(rand()%2)==1) ap = &a; else ap = &b; ap->x=13; A a(10); B b(20); A *ap;

14 Neue Frage

15 Welcher Wert welcher Speicherzelle wird durch die folgenden Anweisungen links verändert ? Auf welches Objekt (a oder b) zeigt ap ? aus Platzgründen: hier steht wie vorher: rand()%2 = =1 Vom Zufall abhängig, zeigt ap entweder auf das Objekt a oder auf das Objekt b. Adr a 0100x10 hallo() Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() Adr ap 0300? if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

16 Angenommen, ap zeigt auf b. Welchen Wert hat dann ap ? Adr a 0100x10 hallo() Adr ap 0300? Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

17 Adr a 0100x10 hallo() Adr ap 0300 Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

18 Adr a 0100x10 hallo() Adr ap Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

19 Auf welches hallo() würde dann die Anweisung ap->hallo() zugreifen ? Es gibt 2 Möglichkeiten: b.A::hallo() oder b.B::hallo() Da sich der Compiler schon beim Compilieren (und nicht erst während der Laufzeit) entscheiden muss, kann es nicht... Adr a 0100x10 hallo() Adr ap Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

20 .... B::hallo() sein, da diese Methode (falls ap auf a zeigt) nicht zu A gehört. Dagegen existiert (egal ob ap auf a oder b zeigt) immer die Methode A::hallo(). Diesen Vorgang des Compilers nennt man early binding (frühe Bindung). dieses hallo() existiert in a und b Adr ap Adr a 0100x10 hallo() Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

21 Also: Der Typ der Zeigervariablen, hier also A, und nicht der Typ des Objekts auf den ap während der Laufzeit zeigt, hier also b, bestimmt welches Mitglied (Member) von *ap angesprochen wird. Adr a 0100x10 hallo() Adr ap Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

22 Mögliche Speicherbelegung beim obigen Programm (hier nochmals das Programm)

23 int main(){ A a(10); B b(20); A *ap; srand((unsigned)time(NULL)); if(rand()%2==1){ ap = &a; } else{ ap = &b; } ap->x = 13; ap->hallo(); return(0); }

24 Annahme: 1) Die Adressen wurden willkürlich gewählt. In der 4. Spalte stehen die Werte also die Inhalte der Adressen nachdem die letzte Anweisung des Programms abgearbeitet wurde. 2) Zufallsbedingt soll der Körper des else Teils der if-Verzweigung (also ap = &b) ausgeführt werden.

25 AdresseSymbolbestehtInhalt 0100ax bA::x13 B::x19 y ap A::hallo() Anweisungen B::hallo() Anweisungen

26 Neue Frage

27 Wie kann man erreichen, dass bei einem Verweis auf ein Objekt die Methode der Klasse dieses Objektes zur Laufzeit aufgerufen wird und nicht die gleichnamige Methode der Klasse des Typs des Verweises beim Compilieren ? Kurz: Wie kann man early binding umgehen ? Wie wird dies programmtechnisch realisiert ?

28 Angenommen, ap zeigt zufallsbedingt auf a. Dann soll die Anweisung ap->hallo() auf die folgende Methode zugreifen: Die Methode hallo(), der Klasse des Objekts, auf das ap während der Laufzeit zeigt, also A::hallo(). Adr a 0100x10 hallo() Adr ap Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

29 Angenommen, ap zeigt zufallsbedingt auf b. Dann soll die Anweisung ap->hallo() auf die folgende Methode zugreifen: Die Methode hallo(), der Klasse des Objekts, auf das ap während der Laufzeit zeigt, also B::hallo(). Adr a 0100x10 hallo() Adr ap Adr b 0200A::x18 x19 y20 A::hallo() B::hallo() if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

30 Das dazugehörige Programm ist das Gleiche wie oben, nur dass die Methode hallo() bei der Deklaration den Bezeichner virtual bekommt.

31 Das Programm

32 #include "stdafx.h" #include #include using namespace std;

33 class A{ public: A(int i); virtual void hallo(); int x; }; class B: public A{ public: B(int i); virtual void hallo(); int x; int y; }; Durch den Bezeichner virtual wird hallo() eine virtuelle Funktion. Die Verwendung von virtual ist nur innerhalb einer Klassendeklaration zulässig. Der Bezeichner virtual vererbt sich und muß daher nicht mehr (kann aber) in den Subklassen wiederholt werden.

34 A::A(int i){ x = i; }; void A::hallo(){ cout <<"Ich bin A und " << "x= " << x << endl; }; B::B(int i):A(i-2){ x = i-1; y = i; }; void B::hallo(){ cout << "Ich bin B" << "x=" << x << "y=" << y << endl; };

35 int main(){ A a(10); B b(20); A *ap; srand((unsigned)time(NULL)); if(rand()%2==1){ ap = &a; } else{ ap = &b; } ap->x = 13; ap->hallo(); return(0); }

36 Neue Frage

37 Wie wird dies technisch im Speicher realsiert ?

38 vt_A ist ein Verweis (Adresse) auf eine Tabelle (virtual function pointer table), in der wiederum die Adressen der virtuellen Methoden der Klasse A stehen, hier also die Adresse der Methode A::hallo() vt_B ist ein Verweis (Adresse) auf eineTabelle (virtual function pointer table), in der wiederum die Adressen der virtuellen Methoden der Klasse B stehen, hier also die Adresse der Methode B::hallo() Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap 0300? Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

39 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap 0300? Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap; Angenommen, ap zeigt zufallsbedingt auf a. Welchen Wert hat dann ap ?

40 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap 0300 Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

41 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap; Welche Adresse wird dann beim Aufruf von hallo() in der folgenden Anweisung angesprochen ? ap->hallo() ein ?

42 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap; *(ap-4) Welche Methode wird also aufgerufen ? A::hallo()

43 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap 0300? Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap; Angenommen, ap zeigt zufallsbedingt auf b. Welchen Wert hat dann ap ?

44 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap 0300 Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap;

45 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap; Welche Adresse wird dann beim Aufruf von hallo() in der folgenden Anweisung angesprochen ? ap->hallo() ein ?

46 Adr vt_A 0500 A::hallo() Adr vt_B 0600 B::hallo() Adr a 096&vt_A 0100x10 Adr ap Adr b 0196&vt_B 0200A::x18 x19 y20 if(...) ap = &a; else ap = &b; ap->hallo(); A a(10); B b(20); A *ap; *(ap-4) Welche Methode wird also aufgerufen ? B::hallo()

47 Mögliche Speicherbelegung beim obigen Programm (hier nochmals das Programm)

48 Annahme: 1) Die Adressen wurden willkürlich gewählt. In der 4. Spalte stehen die Werte, also die Inhalte der Adressen nachdem die letzte Anweisung des Programms abgearbeitet wurde. 2) Zufallsbedingt soll der Körper der if- Verzweigung (also ap = bp) ausgeführt werden. 3) Zwischen den Zeilen stehen platzbedingt keine (durch... getrennten) weiteren Adressen.

49 AdresseSymbolbestehtInhalt 096a&vt_A x b&vt_B A::x13 B::x19 y ap vt_A &A::hallo() vt_B &B::hallo() A::hallo() Anweisungen 0800 B::hallo() Anweisungen

50 Ist early binding (frühe Bindung) auch einfacher möglich ? (ohne Pointer)

51 Das (einfachere) Programm ist das Gleiche wie oben, nur dass statt dem Pointer *ap ein Objekt der Klasse A verwendet wird.

52 #include "stdafx.h" #include #include using namespace std;

53 class A{ public: A(int i); virtual void hallo(); int x; }; class B: public A{ public: B(int i); virtual void hallo(); int x; int y; }; virtual

54 A::A(int i){ x = i; }; void A::hallo(){ cout <<"Ich bin A und " << "x= " << x << endl; }; B::B(int i):A(i-2){ x = i-1; y = i; }; void B::hallo(){ cout << "Ich bin B" << "x=" << x << "y=" << y << endl; };

55 int main(){ A a(10); B b(20); A z(123); srand((unsigned)time(NULL)); if(rand()%2==1){ z = a; } else{ z = b; } z.x = 13; z.hallo(); return(0); }

56 Warum wird hier kein late Binding gemacht ?

57

58 int main(){ A a(10); B b(20); A z(123); srand((unsigned)time(NULL)); if(rand()%2==1){ z = a; } else{ z = b; } z.x = 13; z.hallo(); return(0); } Durch diese Deklaration ist das Objekt z immer vom Klassentyp A. Deshalb wird hier immer early binding gemacht, ganz egal, ob man der Methode hallo den Bezeichner virtual gegeben hat.


Herunterladen ppt "Early binding (frühe Bindung) late binding (späte Bindung)"

Ähnliche Präsentationen


Google-Anzeigen