Object-Oriented Programming
Total Page:16
File Type:pdf, Size:1020Kb
CSE 143 Introduction •Classes have given us tremendous benefit •Encapsulation: make details of implementation and representation private Object-Oriented •Classes help break down and organize the task of Programming writing a program •Classes are designed to enable other benefits [Chapter 8] •Inheritance (subclassing) •Dynamic dispatch (polymorphism) •Two very powerful programming tools! •They help us write less code 2/20/99 336 2/20/99 337 Classes Using Other Classes Hierarchies of Organization •We've seen one way that a class can make use of •Often, we classify things in a hierarchy from another class general to specific •Use an instance of that class as a member variable Animal class PolyLine Mammal Fish Reptile { Canine Feline private: Tuna Shark PointArray pa; }; Wolf Dog Cat Iguana Croc •Objects have more of a "is-a-kind-of" relationship •We might call this a "has-a" relationship • • A Dog "is-a-kind-of" Canine, a Shark "is-a-kind-of" A PolyLine "has-a" PointArray Animal •This is often just called a “is-a” relation 2/20/99 338 2/20/99 339 Inheritance Example: A Point Class •Inheritance is a way to encode the "is-a-kind-of" •Let's say we had the relation in OO languages following class • class Point •Shark declares that it "is-a-kind-of" Fish by inheriting We can use inheritance to { create a class of colored public: from it Point( double x, double y ); • points based on this class A derived class inherits from a base class by putting double getX(); ": public BaseClassName" in the class declaration double getY(); GHULYHGÃFODVV EDVHÃFODVV void print( ostream& os ); RUÃVXEFODVV RUÃVXSHUFODVV private: class Shark : public Fish { double xpos; // Shark-specific stuff here double ypos; }; }; 2/20/99 340 2/20/99 341 CSE 143 1 ColorPoint with inheritance Rules of Inheritance class ColorPoint : public Point • { All data and methods in base class (superclass) • public: ColorPoint "is-a" Point ColorPoint( double x, double y, are automatically inherited by derived (sub) class • Therefore ColorPoint has to be Color c ); •Changes in base class are automatically able to do anything Point can // getX() is inherited from Point • All fields and methods of Point // getY() is inherited from Point propagated into derived classes are "inherited" by ColorPoint - // New accessor method for the •Public members of base class visible to derived they are transparently included! // Color field Color getColor(); class and clients that use it • Derived class can add new // We still need to redefine methods, fields // the print method! •Private members of base class still not visible to • Derived class can override base void print( ostream& os ); derived class or clients class behaviour private: // xpos is inherited from Point •Can also declare “protected” members in base // ypos is inherited from Point Color color; class which are visible in derived class, but not }; visible to clients. 2/20/99 342 2/20/99 343 ColorPoint Implementation ColorPoint Client ColorPoint::ColorPoint( double x, double y, Color c ) : Point( x, y ) { Point p( 1.0, 0.0 ); color = c; ColorPoint cp1( 3.14, -45.5, RED ); } // No problem: ColorPoint::print is defined Color ColorPoint::getColor() { cp1.print( cout ); return color; } // No problem: calls Point::getX() and Point::getY() // on Point subset of ColorPoint to access private void ColorPoint::print( ostream& os ) { // xpos and ypos fields os << "(" << getX() << ", " << getY() cout << cp1.getX() << " " << cp1.getY() << endl; << ")/" << color; } // p can refer to any Point, including one that is // actually a ColorPoint. But p can only be used to • // access fields that belong to all Points (i.e., New notation: “: member(values, …)” specifies // can’t be used to access getColor base class constructor to initialize base class p = cp1; fields in derived class object 2/20/99 344 2/20/99 345 Invoking Overriden Methods Scope Resolution •Observation: ColorPoint::print does the same •It turns out that the :: operator allows us to thing as Point::print, and then prints out a Color explicitly call an overriden method from the •So perhaps we can call Point::print from within derived class ColorPoint::print void ColorPoint::print( ostream& os ) { •What happens if we try it this way? Point::print( os ); os << ", " << Color; } void ColorPoint::print( ostream& os ) { •BaseClass::method( arguments ) can be used print( os ); // trying to call print method in superclass BaseClass os << ", " << Color; as long as really is a parent class } (either direct base class or more distant ancestor) 2/20/99 346 2/20/99 347 CSE 143 2 Inheritance and Constructors Substituting Derived Classes •Constructors are not inherited! •Recall that an instance of a •Can’t be, because their name specifies which class derived class can always be substituted for an Point p( 1.0, 9.0 ); they’re part of! ColorPoint cp( 6.0, 7.0, red ); instance of a base class • p = cp; Instead, constructor of base class is called • Derived class guaranteed to automatically before constructor of derived class have (at least) the same data void printPoint( Point pt ) • and interface as base class { Can indicate base class constructor explicitly using the • pt.print( cout ); “:class(arguments)” notation to pass parameters (like in But you may not get the } behaviour you want! ColoredPoint example) printPoint( p ); •If omitted, default constructor of base class is called printPoint( cp ); •Constructors are called in "inside-out" order 2/20/99 348 2/20/99 349 Pointers And Inheritance Static And Dynamic Types •You can also substitute a •In C++, every variable has a static and a dynamic pointer to a derived class type for a pointer to a base Point *pptr = new Point( 1.0, 9.0 ); ColorPoint *cpptr = •Static type is declared type of variable class new ColorPoint( 6.0, 7.0, red ); Every variable has a single static type that never changes • There's still that guarantee Point *fooptr = cpptr; •Dynamic type is type of object the variable actually about data and interface void printPoint( Point *ptr ) • Also holds for reference types { contains or refers to ofstream ofs( "point.out" ); Dynamic type can change during the program! • No information disappears!! ptr->print( ofs ); • ofs.close(); •Up to now, these have always been identical Unfortunately, we still have } the same problems… •But not any more! printPoint( pptr ); printPoint( cpptr ); Point *myPointPointer = new ColorPoint( 3.14, 2.78, green ); 2/20/99 350 2/20/99 351 Static Dispatch Dynamic Dispatch •"Dispatching" is the act of deciding which piece of •C++ has a mechanism for declaring individual code to execute when a method is called methods as dynamically dispatched •Static dispatch means that the decision is made •If an overriding function exists, call it statically, i.e. at compile time •In base class, label the function with virtual •Decision made based on static type of receiver keyword Point *myPointPointer = new ColorPoint( 3.14, 2.78, green ); •Overriding versions in subclasses may or may not have // myPointPointer is a Point*, so call Point::print the virtual keyword; but use consistently for better style myPointPointer->print( cout ); •Rule of thumb: If you may ever need to override a •Idea: make the decision at runtime, based on the method, make it virtual! dynamic type of the object •Even safer rule: Unless you have a good reason not to, member functions in a class hierarchy should be virtual. 2/20/99 352 2/20/99 353 CSE 143 3 Example Of Dynamic Dispatch Dynamically-Dispatched Calls Point *p = new ColorPoint( 3.13, 5.66, ochre ); class Point { p->print( cout ); public: virtual void print( ostream& os ); … •The compiler notices that Point::print is defined }; as virtual class ColorPoint : public Point { •Instead of just calling Point::print, it inserts public: virtual void print( ostream& os ); extra code to look at information attached to the … new }; object by to decide what function to call •This is slightly slower than static dispatch Point *p = new ColorPoint( 3.13, 5.66, ochre ); •Almost always too minor a speed penalty to worry about p->print( cout ); // calls ColorPoint::print( ) 2/20/99 354 2/20/99 355 A User-Interface Example Abstract Classes •Many user interface class Widget { • public: Some classes are so abstract that instances of toolkits are void getPosition( int& x, int& y ); them shouldn't even exist implemented as class virtual void draw( Screen& theScreen ); … •What does it mean to have an instance of Widget? of hierarchies private: Animal? •Helps manage int xpos; int ypos; • complexity }; An abstract class is one that should not or can not be instantiated - it only defines an interface class Button : public Widget { • public: • Question: how should virtual void draw( Screen& theScreen ); A concrete class can have instances we implement … • }; It may not make sense to attempt to fully Widget::draw? implement all functions in an abstract class class Toolbar : public Widget { public: •What should Widget::draw do? virtual void draw( Screen& theScreen ); }; 2/20/99 356 2/20/99 357 Pure Virtual Functions Summary •A “pure virtual” function is not implemented in the base class - must implement in derived class •Object-Oriented Programming •Syntax: append "= 0" to base method declaration •Inheritance class Widget { •Use for "is-a-kind-of", not "has-a" relations public: virtual void draw( Screen& theScreen ) = 0; •Classification hierarchies }; •Base class (superclass), derived class (subclass) •Compiler guarantees that class with pure virtual •Overriding functions functions cannot be instantiated • • Static and dynamic types If you call a pure virtual function, you’ll use the • version from some derived class Dynamic Dispatch • Widget *w = new Button(); Virtual functions w->draw( myScreen ); •Abstract classes, pure virtual functions 2/20/99 358 2/20/99 359 CSE 143 4.