Jeff West - Quiz Section 12 CSE 143 Section AD Quiz Section 12 7/26/2001 Jeff West - Quiz Section 12
Jeff West - Quiz Section 12 Announcements Quiz at the end of section on Inheritance and Dynamic Dispatch 7/26/2001 Jeff West - Quiz Section 12
Jeff West - Quiz Section 12 Substitution A derived class can ALWAYS be substituted for a base class. However, the behavior of a substituted class depends on the type of the methods you’re calling. 7/26/2001 Jeff West - Quiz Section 12
What does this print to the screen? (No virtual functions) void Shape::draw() { cout << “Hi, I’m a shape!”; } void Rectangle::draw() { cout << “Hi, I’m a rectangle!”; void drawShape(Shape myShape) { myShape.draw(); Shape myShape; Circle myRectangle(GREEN, 20, 10); myShape = myRectangle; drawShape(myShape); drawShape(myRectangle); 7/26/2001 Jeff West - Quiz Section 12
And this??? (No virtual functions) void Shape::draw() { cout << “Hi, I’m a shape!”; } void Rectangle::draw() { cout << “Hi, I’m a rectangle!”; void drawShape(Shape* myShape) { myShape->draw(); Shape* myShape; Circle* myRectangle = new Rectangle(GREEN, 20, 10); myShape = myRectangle; drawShape(myShape); drawShape(myRectangle); 7/26/2001 Jeff West - Quiz Section 12
What if we want the drawShape function to… We can make it so that the drawShape function would call the draw() method of the run-time type that is passed in! To do this, we need only to declare the function virtual in the base class (Shape in our example)… 7/26/2001 Jeff West - Quiz Section 12
What does this print to the screen? (Virtual functions!) void Shape::draw() { cout << “Hi, I’m a shape!”; } void Rectangle::draw() { cout << “Hi, I’m a rectangle!”; void drawShape(Shape myShape) { myShape.draw(); Shape myShape; Circle myRectangle(GREEN, 20, 10); myShape = myRectangle; drawShape(myShape); drawShape(myRectangle); 7/26/2001 Jeff West - Quiz Section 12
Jeff West - Quiz Section 12 To take advantage… To take advantage of virtual functions you need to use pointers to objects. Otherwise, information is lost! The most common use for all of this is to have one large array of one object type (e.g. vehicles) that have many “sub-types” that behave differently (trucks, cars, busses)… 7/26/2001 Jeff West - Quiz Section 12
And this??? (Virtual functions!) void Shape::draw() { cout << “Hi, I’m a shape!”; } void Rectangle::draw() { cout << “Hi, I’m a rectangle!”; void drawShape(Shape* myShape) { myShape->draw(); Shape* myShape; Circle* myRectangle = new Rectangle(GREEN, 20, 10); myShape = myRectangle; drawShape(myShape); drawShape(myRectangle); 7/26/2001 Jeff West - Quiz Section 12
Pure Virtual Functions (1) What if you never want the ability to create a shape, because it doesn’t make sense for a shape to “draw” itself… You’d call Shape an abstract class, intended only to be a skeleton for derived classes. Make functions that need to be in a child class but can’t be defined in the Shape class pure virtual! 7/26/2001 Jeff West - Quiz Section 12
Pure Virtual Functions (2) Class Shape { public: … virtual void draw() = 0; }; 7/26/2001 Jeff West - Quiz Section 12
Jeff West - Quiz Section 12 But Why??? Without having some sort of draw() function in EVERY Shape class instance, you couldn’t: void Rectangle::draw() { cout << “Hi, I’m a rectangle!”; } void drawShape(Shape* myShape) { myShape->draw(); Shape* myShape; Circle* myRectangle = new Rectangle(GREEN, 20, 10); myShape = myRectangle; drawShape(myShape); drawShape(myRectangle); 7/26/2001 Jeff West - Quiz Section 12
A bit of cleaning up to do… Always make your destructors virtual! This ensures that all dynamic memory in inherited classes is taken care of. Remember how constructors of derived classes always call the constructors of their base class before executing? Destructors always call the destructors of their base class after executing! 7/26/2001 Jeff West - Quiz Section 12