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

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

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

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

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

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

Ausgangspunkt sind wieder die Klassen der letzten Präsentation:

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

#include "stdafx.h"#include <iostream>#include <time.h>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;};

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

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;};

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

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 a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300 ?

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

Angenommen, ap zeigt auf b. Welchen Wert hat dann ap ?

Adr a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300 ?

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

Angenommen, ap zeigt auf b. Welchen Wert hat dann ap ?

Adr a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

Adr a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300 0200

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

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 a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300 0200

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

.... 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 a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300 0200

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

Also wird der Wert von x im Objekt b verändert auf:

Adr a0100 x 10

Adr b0200 A::x 18

x 19y 20

Adr ap0300 0200

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

Adr a0100 x 10

Adr b0200 A::x

x 19y 20

Adr ap0300 0200

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

Adr b0200 A::x 13

x 19y 20

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 ap0300 0200

Adr a0100 x 10

if(rand()%2)==1) ap = &a;else ap = &b;ap->x=13;

A a(10);B b(20);A *ap;

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

Neue Frage

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

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 a0100 x 10

hallo()

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

Adr ap0300 ?

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Angenommen, ap zeigt auf b. Welchen Wert hat dann ap ?

Adr a0100 x 10

hallo()

Adr ap0300 ?

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Adr a0100 x 10

hallo()

Adr ap0300

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Adr a0100 x 10

hallo()

Adr ap0300 0200

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

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 a0100 x 10

hallo()

Adr ap0300 0200

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

.... 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 ap0300 0200

Adr a0100 x 10

hallo()

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

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 a0100 x 10

hallo()

Adr ap0300 0200

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Mögliche Speicherbelegung beim obigen Programm (hier

nochmals das Programm)

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

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);}

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

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.

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

Adresse Symbol besteht Inhalt0100 a x 10... ... ... ...0200 b A::x 13

B::x 19y 20

... ... ... ...0300 ap 0200... ... ... ...0500 A::hallo() Anweisungen

... ... ... ...0600 B::hallo() Anweisungen

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

Neue Frage

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

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 ?

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

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 a0100 x 10

hallo()

Adr ap0300 0100

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

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 a0100 x 10

hallo()

Adr ap0300 0200

Adr b0200 A::x 18

x 19y 20A::hallo()B::hallo()

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

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

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

Das Programm

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

#include "stdafx.h"#include <iostream>#include <time.h>

using namespace std;

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

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.

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

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;};

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

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);}

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

Neue Frage

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

Wie wird dies technisch im Speicher realsiert ?

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

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_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 ?

Adr b0196 &vt_B0200 A::x 18

x 19y 20

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 ?

Adr b0196 &vt_B0200 A::x 18

x 19y 20

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 ?

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300

Adr b0196 &vt_B0200 A::x 18

x 19y 20

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 100

Adr b0196 &vt_B0200 A::x 18

x 19y 20

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 ?

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 100

Adr b0196 &vt_B0200 A::x 18

x 19y 20

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

*(ap-4)

0100

096

0500

Welche Methode wird also aufgerufen ?

A::hallo()

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 ?

Adr b0196 &vt_B0200 A::x 18

x 19y 20

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 ?

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300

Adr b0196 &vt_B0200 A::x 18

x 19y 20

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 200

Adr b0196 &vt_B0200 A::x 18

x 19y 20

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 ?

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

Adr vt_A0500 A::hallo()

Adr vt_B0600 B::hallo()

Adr a096 &vt_A0100 x 10

Adr ap0300 200

Adr b0196 &vt_B0200 A::x 18

x 19y 20

if(...) ap = &a;else ap = &b;ap->hallo();

A a(10);B b(20);A *ap;

*(ap-4)

0200

0196

0600

Welche Methode wird also aufgerufen ?

B::hallo()

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

Mögliche Speicherbelegung beim obigen Programm (hier

nochmals das Programm)

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

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.

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

Adresse Symbol besteht Inhalt096 a &vt_A 05000100 x 100196 b &vt_B 06000200 A::x 13

B::x 19y 20

0300 ap 02000500 vt_A &A::hallo() 07000600 vt_B &B::hallo() 08000700 A::hallo() Anweisungen

0800 B::hallo() Anweisungen

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

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

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

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

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

#include "stdafx.h"#include <iostream>#include <time.h>

using namespace std;

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

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

virtual

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

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;};

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

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);}

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

Warum wird hier kein late Binding gemacht ?

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

Warum wird hier kein late Binding gemacht ?

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

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.