Dynamic Binding Implementation Object Oriented Programming 236703 Spring 2008 1
Implementation of Virtual Functions class Ellipse { //... public: E 1 virtual void draw() const; draw E + virtual void hide() const; 2 hide virtual void rotate(int); + P } E1, E2, *P; rotate + Ellipse class Circle: public Ellipse { //... public: virtual void rotate(int); virtual Point centre(); } C1, C2, C3; C 1 C 2 C 3 Circle rotate ++ centre +
The Virtual Methods Table P C++ Jargon: vptr and vtbl E1 E2 C1 C2 C3 Ellipse VMT draw hide rotate Circle VMT draw hide rotate centre Ellipse :: draw Ellipse :: hide Circle :: centre Ellipse :: rotate Circle :: rotate
P->rotate() P E1 E2 C1 C2 C3 Ellipse VMT draw hide rotate Circle VMT draw hide rotate centre Ellipse :: draw Ellipse :: hide Circle :: centre Ellipse :: rotate Circle :: rotate
Location of VPTR #1/2 BorlandStyle: at the beginning of an object. Intuitive and simple (usually) Problematic, if the base class does not have any virtual functions: p Base vtbl Base Derived Derived vptr base object additional data members When converting a pointer to the derived class into a pointer to the base, the compiler must add an offset to skip over the vptr. Thisoffset mustbe subtracted in downcasting. The compiler must also do a null check, because the offset should not be added in case of a null pointer.
Location of VPTR #2/2 Gnu Style: when first virtualfunction isencountered p vtbl Base Base Deriveded Derived base object vptr additional data members Not so simple or intuitive. Virtual function call is a bit more complicated. Compiler must have a deterministic algorithm for locating the vptr: If the function called is not virtual in the static type of the pointer use static binding If the function is virtual add to the pointer the offset corresponding to the size of the most derived virtual free super class of the static type of the pointer Casting is so much simpler. No need to add or subtract any offset in up or down casting.
Dynamic Binding and Dynamic Typing Dynamic Typing: no constraints on the values stored in a variable. Usually implies reference semantics Run time type information: dynamic type is associated with the value. There is no notion of static type to be associated with a variable. No type safety: run time error if an object doesn't recognize a message.
Oliver Twist instance_of other instance variables... Novel subclass_of dispatch_table other class variables... #set_author #get_author th Dispatch Tables Document subclass_of dispatch_table... other class variables -------------- ------ ---- ---- ----- -- ----- ------- ------------- ------ ------------- #set_year #get_year... ------------ -------- --------- ---- ------------- ------------- ---- ------- Object subclass_of dispatch_table other class variables #print... ------- --------- ---- ------------- Used in dynamic type systems Support: Runtimeintroduction introduction of new types Runtime changes to type hierarchy Method not found error messages Space Efficiency: optimal! Time Efficiency: lousy; mitigated by a cache of triples: Class where search started Selector searched Address of method found
Binding within Constructors How is an object of class B derived from class A initialized? In C++ and Java, the constructor of A is invoked before the constructor of B Why? So the B constructor never sees uninitialized attributes What happens if A s constructor invokes a pp virtual function?
Binding within Constructors C++ The binding of function calls within constructors is static B s memory has not been initialized iti yet struct A { int x; virtual void f() {cout << x= << x ;} A() : x(1) {f();} }; struct t B: A { public: int y; virtual void f() {cout << y= << y;} B() : y(2){}; }; The output of new B(); is: x=1
Problem with Static Binding within struct A { virtual void f() = 0; A() {f();} }; Constructors t struct B: A { public: virtual void f() {cout << B s f ;} }; What happens in new B();? Some compilers do not allow calling a pure virtual function directly from constructors However, nesting such a call in a chain of function calls it will usually compile
Binding within Constructors Java The binding of function calls within constructors is dynamic An initialization iti phase precedes the constructor t invocation class A { private int x=1; public void f() {System.out.print( x= +x);} public A() {f();} } class B extends A { private int y=2; public void f() {System.out.print( y= +y);} public B() {} } The output of new B(); is: y=0
Problem with Dynamic Binding within Constructors class A { public A() {System.out.print(toString());} } class B extends A { private String s = Class B public String tostring() {return s.tolowercase();} } What happens in new B();? s is initialized to null when A s constructor is invoked B s tostring() is invoked from A s constructor The result: NullPointerException