C++ Run-Time Representation Point object Point vtable Code for move C++ Part x y CSCI 4 Stephen Freund ColorPoint object x 4 y 5 c red ColorPoint vtable Code for move Code for darken Data at same offset Function pointers at same offset! C++:Point Point *pt = ; pt -> move(,10); pt must be a Point or a subclass of Point All subclasses of Point use same vtable order for Point methods. Compiler can hard-code in vtable offset: (pt->vtable[0])(pt,, 10)! Smalltalk: pt movedx: Dy: 10 pt could be any object with movedx:dy: in protocol No info about layout. Must search dictionary. (super class) Point object Point class Template x y Method dictionary newx:y: draw movedx:dy: Could we put methods at same offset? Class A def movedx:dy: Class C Class B def movedx:dy: def print def print! Static type info about object layout more efficient lookup but less expressive " unrelated classes cannot be subtypes! Things to think about: How Java interface declarations fit into this picture? How do Scala traits? 1
Non-Virtual Methods int getx(); virtual void move(int dx, int dy); ; Point *pt = ; pt -> getx(); Compiler hard-codes in direct jump: Point::getX(pt,, 10)! Why useful? class InputStream { virtual int read(); InputStream virtual String readline(); virtual int readint(); virtual long readlong(); FileInputStream SocketInputStream ; ConsoleInputStream String InputStream::readLine() { String result = ""; while (true) { int ch = read(); if (ch == '\n') break; result += ch; return result; class InputStream { virtual int read(); String readline(); int readint(); long readlong(); ; String InputStream::readLine() { String result = ""; while (true) { int ch = read(); if (ch == '\n') break; result += ch; return result; FileInputStream InputStream ConsoleInputStream SocketInputStream class FileInputStream : public InputStream { virtual int read() { ; class SocketInputStream : public InputStream { virtual int read() { ; Overloading vs. Virtual Methods void printclass() { cout << "Point"; virtual void printclassvirtual() { cout << "Point"; ; void printclass() { cout << "ColorPoint"; virtual void printclassvirtual() { cout << "ColorPoint"; ; Point *p = new Point(); p->printclassvirtual(); p->printclass(); cp->printclassvirtual(); cp->printclass(); Overloading vs. Virtual Methods void printclass() { cout << "Point"; virtual void printclassvirtual() { cout << "Point"; ; void printclass() { cout << "ColorPoint"; virtual void printclassvirtual() { cout << "ColorPoint"; ; Point *p = new ColorPoint(); p->printclassvirtual(); p->printclass();
Overloading Based on Arguments class OutputStream { void println(int v); void println(double d); void println(string s); void println(object o); OutputStream *out = ; out->println(); out->println("moo"); Overriding vs. Overloading (Can be painful to think about) virtual boolean equals(point *p) // 1 { ; virtual boolean equals(point *p) // { Object *obj = "cow"; out->println(obj); // String <: Object ; virtual boolean equals(colorpoint *cp) // { Point *p1 = new Point(); Point *p = new ColorPoint(); Point *p1 = new Point(); Point *p = new ColorPoint(); p1->equals(p1); p1->equals(p); p1->equals(cp); p1->equals(p1); p1->equals(p); p1->equals(cp); p->equals(p1); p->equals(p); p->equals(cp); p->equals(p1); p->equals(p); p->equals(cp); cp->equals(p1); cp->equals(p); cp->equals(cp); cp->equals(p1); cp->equals(p); cp->equals(cp); Different Notions of Subtyping! Smalltalk protocol conformance A <: B if protocol of B protocol of A! Java A <: B if A extends B A <: I if A implements I! C++ A <: B if B is public base class of A class A : public B { è A <: B class A : private B { è A <: B Private vs Public Base Classes class DEBuffer { void addfirst(int v); void addlast(int v); int removefirst(); int removelast(); int elems[]; int size; class Stack : private DEBuffer { void push(int v) { addlast(v); int pop() { return removelast(); void invert() { class Queue : private DEBuffer { void enqueue(int v) { int dequeue() {
Why Not Just Use Delegation? Abstract Base Classes class DEBuffer { void addfirst(int v); void addlast(int v); int removefirst(); int removelast(); int elems[]; int size; class Stack { private: DEBuffer *delegate; void push(int v) { delegate->addlast(v); int pop() { return delegate->removelast(); void invert() { class Expr { private: Type t; virtual int eval() = 0; virtual int leaves() { return 0; class Plus : public Expr { private: Expr *left; Expr *right; virtual int eval() { return left->eval() + right->eval(); Expr *e = new Plus(); // OK Expr *f = new Expr(); // BAD virtual Point *copy() { virtual ColorPoint *copy() { Point *copy = pt->copy();! f1 : int # Point! f : int # ColorPoint! f1 : Point # int! f : ColorPoint # int 4
! f1 : ColorPoint # int! f : Point # int! Okay when C <: A and B <: D ColorPoint # Point ColorPoint # ColorPoint Point # Point Point # ColorPoint virtual Point *copy() { virtual ColorPoint *copy() { Point *copy = pt->copy(); yes virtual boolean equals(point *pt) { virtual boolean equals(colorpoint *cpt) { ColorPoint *cpt; Point *pt = cpt; if (pt -> equals(pt)) { Assume this overrides def from superclass no Stack Allocated Objects void m() { Point *ref = new Point(1,1); Point pt(,); ColorPoint cpt(4,5,red); control link ref->move(5,5); pt.move(10,10); cpt.getcolor(); delete ref; pt cpt ref x y x 4 y 5 col red x 1 y 1 Point vtable CPoint vtable 5