Object-oriented Languages Compiler Baojian Hua [email protected] OOP So far, we’ve covered most C features Object-oriented languages are more and more popular due to the industry push expression, statement, function this time: compile the class-based OO lang’ Roadmap: class and objects inheritance & virtual functions RTTI & reflection next time: exception Class “Point” class P2 { int x; int y; P2 (int x, int y) { this.x = x; this.y = y; } void print () { println (this.x, this.y); } } Compiling to C // Close all functions: class P2 { int x; int y; P2 (P2 this, int x, int y) { this.x = x; this.y = y; } void print (P2 this) { println (this.x, this.y); } } Compiling to C // Hoisting: class P2 { int x; int y; } P2 (P2 this, int x, int y) { this.x = x; this.y = y; } void print (P2 this) { println (this.x, this.y); } Compiling to C // In C’s syntax: struct P2 { int x; int y; }; typedef struct P2 *P2; P2 (P2 this, int x, int y) { this->x = x; this->y = y; } P2 x y Client Code // Client code: P2 p = new P2 (3, 4); p.print (); // compiles to: P2 p = malloc (sizeof (*p)); P2(p, 3, 4); print(p); P2 x y Moral Difference with C? In history, some compilers compile OO to C class = struct + function code object = a region of memory in mem (malloc?) e.g., Bjarne Stroustrup et.al’s Cfront But how does this work with other features? inheritance dynamic dispatch Inheritance // Single inheritance: class P3 extends P2 { int z; P3 (int x, int y, int z) {…} // Note: this is not named “print”. Why? void print3d () { println (this.x, this.y, this.z); } } Prefixing // A technique called prefixing: class P3 extends P2 { int x; int y; int z; void print () { … } void print3d () { … } } Compiling to C struct P2 { int x; int y; }; struct P3 { int x; int y; int z; }; P2 x y P3 void P2_print (P2 this) {…} void P3_print (P2 this) {…} void print3d (P3 this) {…} x y z Q: can we put “z” before “x” or “y”? Virtual functions class P2 { …; void print () {…} } class P3 extends P2 { …; void print () {…} } Dynamic dispatch class P2 { …; void print () {…} } class P3 extends P2 { …; void print () {…} } P2 p; p = new P2 (); p.print (); p = new P3 (); p.print (); Compiling dynamic dispatch Variable’s compile-time type is insufficient to determine the specific function to be called We need store in the object the information required The data structure for this purpose is the famous virtual function table or vtable Function call becomes an indirection via vtable Vtable class P2 { …; void print () {…} } vptr x y vptr class P3 extends P2 { …; void print () {…} } P2_print x y z P3_print General Scheme class A { int x1; …; int xn; vptr x1 … xn A_f1 … A_fn vtable void f1 (…){} … void fn (…){} }; Client Code // Client code: P2 p; p = new P2 (3, 4); p.print (); vptr x P2_print y p // compiles to: P2 p; p = malloc (sizeof (*p)); // how many bytes? P2(p, 3, 4); ((p->vptr)[0]) (p); // where’s “print”? Client Code // Client code: P2 p; p = new P2 (3, 4); p.print (); p = new P3 (7, 8, 9); p p.print (); vptr 7 8 9 vptr P2_print x y P3_print Moral Dynamic dispatch is polymorphism: subtyping poly’ No free lunch: extra space to store vtable dynamic dispatch via indirection (slow?) “All problems in computer science can be solved by another level of indirection!” -- Butler Lampson OO = Pointer + Virtual Functions RTTI & reflection RTTI: Run Time Type Identification Reflection: Ability to identify the type (class) of an object at runtime more powerful, can (mostly) do anything at runtime What are they used for? Type identification Inheritance hierarchy string based method invocation exception handling … RTTI P2 p; …; Class c = p.getClass (); println (c.getClassName()); vptr x y meta name P2_print … … “P2” Reflection P2 p; …; Class c = p.getClass (); println (c.getClassName()); c.getMethod (“print”, null); vptr x y meta name P2_print “print”, p … “P2” Case study: Visual studio C++ (Microsoft) Multiple Inheritance Template
© Copyright 2025 Paperzz