Presentation is loading. Please wait.

Presentation is loading. Please wait.

CSCE 121:509-512 Introduction to Program Design and Concepts Dr. J. Michael Moore Spring 2015 Set 13: Design of Classes CSCE 121-200: Set 13: Design of.

Similar presentations


Presentation on theme: "CSCE 121:509-512 Introduction to Program Design and Concepts Dr. J. Michael Moore Spring 2015 Set 13: Design of Classes CSCE 121-200: Set 13: Design of."— Presentation transcript:

1 CSCE 121:509-512 Introduction to Program Design and Concepts Dr. J. Michael Moore Spring 2015 Set 13: Design of Classes CSCE 121-200: Set 13: Design of Classes 1

2 CSCE 121:509-512 Set 13: Design of Classes Considerations when Designing Classes Library design considerations Class hierarchies (inheritance) Graph library as a running example 2

3 CSCE 121:509-512 Set 13: Design of Classes Ideal Design Represent concepts of application domain directly in code Examples for graphics: – Window – Line – Point – Color 3

4 CSCE 121:509-512 Set 13: Design of Classes Naming is Important! Give logically identical operations the same name Examples: – draw_lines() does the drawing – move(dx,dy) does the moving – add(p) adds some p (e.g., a Point) – consistent names for getting and setting properties s.color() to get and s.set_color() to set 4

5 CSCE 121:509-512 Set 13: Design of Classes Naming is Important! Give logically different operations different names Examples: – add(p) adds p by copying p into the object – but we use attach(s) on the window because we need to create a reference, not a copy – we can change a displayed object after attaching it but not after adding it 5 &ln ln: win: (100,200) p1: (200,300) p2: attach() add() (100,200) (200,300)

6 CSCE 121:509-512 Set 13: Design of Classes Expose Data Uniformly Data should be private – prevents inadvertent changes – use public get and set functions – Examples: Circle c{Point{100,200},50}; // constructors c.set_radius(c.radius()*2)); // doubles c’s radius c.r = -9; // r is private to Circle, doesn’t compile Functions can be private or public – public for interface – private if used only inside the class 6

7 CSCE 121:509-512 Set 13: Design of Classes Advantages of Private We can change implementation after release – Ex: could replace FLTK with another library We can provide checking in access functions – Ex: not yet done systematically in ours  We can give nicer names – Ex: s.add(x) instead of s.points.push_back(x) We can enforce desired properties – Ex: immutability of certain shapes, like Rectangle ; cannot change relative position of points 7

8 CSCE 121:509-512 Set 13: Design of Classes Systematic Interfaces Make interfaces “regular” Use same conventions as much as possible – For Line, Mark, Circle, Rectangle,... constructors, first parameter is a Point Make interfaces clear and unambiguous Rectangle r1{Point{100,200},200,300}; // versus Rectangle r2{100,200,200,300}; // ?? 8

9 CSCE 121:509-512 Set 13: Design of Classes A Library A collection of classes and functions meant to be used together – as building blocks for applications – to build more such “building blocks” A good library models some aspect of a domain – Doesn’t try to do everything – our graphics library aims at simplicity and small size for graphing data and providing a very simple GUI The classes and functions of a library are designed to work together – should exhibit a uniform style (“regularity”) 9

10 CSCE 121:509-512 Set 13: Design of Classes Class Shape All our shapes are “based on” the Shape class 10 Shape Polygon Text Open_polyline EllipseCircle Marked_polyline Closed_polyline Line Mark Lines Marks Axis Function Rectangle Image

11 CSCE 121:509-512 Set 13: Design of Classes Inheritance Inheritance is a programming language mechanism to reuse and extend existing classes without modifying the original classes Given one class B (the base class), we can define another class D (the derived class) as being derived from B – sometimes B is called the parent class and D the child class 11

12 CSCE 121:509-512 Set 13: Design of Classes Benefit of Inheritance Code reuse: put all the code that is common for several classes into a base class – both state (data) and behavior (functions) Example: Circle, Ellipse, Polygon, Rectangle, etc. all have – location (one or more points) – line color and style – ability to be drawn on the screen 12

13 CSCE 121:509-512 Set 13: Design of Classes Protected Access To help with inheritance, we have a third type of access, in addition to private and public called protected: protected elements of a class are accessible to derived classes but not to other classes 13

14 CSCE 121:509-512 Set 13: Design of Classes Protected Example public members of base class B become public members of derived class D protected members of base class B become protected members of derived class D private members of base class B are not directly accessible from derived class D, but can be accessed by D via calls to public and protected members of B 14 class B { int b_priv; // private by default protected: int b_prot; public: int b_pub; }; // D is derived from B class D : public B { // note “public” int d_priv; // private by default protected: int d_prot; public: int d_pub; };

15 CSCE 121:509-512 Set 13: Design of Classes Protected Example If we declare an object d of type D, d automatically gets – private data member b_priv (although it cannot be accessed directly by code in D) – protected data member b_prot – public data member b_pub – private data member d_priv (which can be accessed directly by code in D) – protected data member d_prot – public data member d_pub 15 class B { int b_priv; // private by default protected: int b_prot; public: int b_pub; }; // D is derived from B class D : public B { // note “public” int d_priv; // private by default protected: int d_prot; public: int d_pub; };

16 CSCE 121:509-512 Set 13: Design of Classes Memory Diagram with Inheritance 16 class B { int b_priv; // private by default protected: int b_prot; public: int b_pub; }; // D is derived from B class D : public B { // note “public” int d_priv; // private by default protected: int d_prot; public: int d_pub; }; //... B b_var; D d_var; d.d_pub; // OK d.b_pub; // OK d.b_priv; // NOT OK b_priv b_prot b_pub b_var b_priv b_prot b_pub d_var d_priv d_prot d_pub

17 CSCE 121:509-512 Set 13: Design of Classes Class vs. Struct with Inheritance An alternative and completely equivalent approach is to define D as a struct instead of class, and use this syntax: – note the missing “public” in the first line 17 // D is derived from B struct D : B { int d_pub; // public by default protected: int d_prot; private: int d_priv; };

18 CSCE 121:509-512 Set 13: Design of Classes Hierarchy of Classes We can build a tree, or hierarchy, of classes being derived from each other. struct E : D { /*... */}; Private members of a class are only accessible to members of that class Protected members of a class are only available to members of that class and members of descendant classes Public members of a class are available everywhere (not just code in inheritance tree) 18

19 CSCE 121:509-512 Set 13: Design of Classes Access Model 19 Public members Protected members Private members All users Derived class’s members Class’s own members

20 CSCE 121:509-512 Set 13: Design of Classes Constructors and Inheritance When a variable of a derived class is declared, default behavior is: – first, default constructor of base class is called – then, (rest of) constructor of derived class is executed If base class does not have a default constructor, or if you want to call a different constructor of the base class, do it like this… 20

21 CSCE 121:509-512 Set 13: Design of Classes Constructors and Inheritance 21 struct B { // has two constructors B() {/*... */} B(int a) { /*... */} }; struct D : B { // derived from B, has one constructor D(int a) : B(a) { /*... */} }; //... D d{0}; // calls D constructor, which first calls the // B constructor with an int argument, and // executes rest of D constructor

22 CSCE 121:509-512 Set 13: Design of Classes Accessing Hidden Names What if derived class D reuses a member name that was also in its base class? You have now hidden all the other members with that same name in ancestor classes of B from D and all of D’s descendant classes However, if D wants to refer to a version in an ancestor class, use the scope-resolution operator :: like this… 22

23 CSCE 121:509-512 Set 13: Design of Classes Accessing Hidden Names If you declare a variable e of type E, then any reference to e.x refer’s to D’s x You cannot get to B’s x from outside the inheritance tree 23 struct B { int x; }; struct D : B { int x; // References to x in here refer to D’s x, not B’s x. // To refer to B’s x, use B::x. }; struct E : D { // No x declared in E. // References to x in here refer to D’s x, not B’s x. // To refer to B’s x, use B::x. };

24 CSCE 121:509-512 Set 13: Design of Classes Abstract Classes A class is abstract if you cannot make any objects of that type So what good is it? – Make objects of derived classes! How do we ensure that no objects of that class can be made? – Make constructor protected! Example: Shape class – Doesn’t make sense to make a Shape 24

25 CSCE 121:509-512 Set 13: Design of Classes Overview of Shape Class Shape holds Points Shape deals with color and style Shape provides a default way of drawing lines – just connects its points 25

26 CSCE 121:509-512 Set 13: Design of Classes Peek Inside Shape Class: Private 26 class Shape { private: vector points; // not used by all shapes Color lcolor; // color for lines and characters Line_style ls; // line style (dashed, dotted, etc.) Color fcolor; // fill color Shape(const Shape&); // prevent copy construction Shape& operator=(const Shape&); // prevent copy assignment

27 CSCE 121:509-512 Set 13: Design of Classes Peek Inside Shape Class: Protected 27 protected: Shape(); // prevent making bare Shape objects; // used by derived classes void add(Point p); // add p to points vector void set_point(int i, Point p); // points[i] = p; // Uses FLTK to connect the points in series; // “virtual” to be explained virtual void draw_lines() const;

28 CSCE 121:509-512 Set 13: Design of Classes Peek Inside Shape Class: Public 28 public: // deals with color and style; // *** calls protected and virtual draw_lines *** void draw() const; virtual void move(int dx, int dy); // virtual to be explained // get and set for lcolor, ls, and fcolor /*... */ // read-only access to points Point point(int i) const { return points[i]; } /* some more */ };

29 CSCE 121:509-512 Set 13: Design of Classes Line Class Simple special case of Shape Inherits all protected (and public) members, including points vector and add() Uses Shape’s draw_lines() 29 struct Line : Shape { Line(Point p1, Point p2) { add(p1); add(p2); } };

30 CSCE 121:509-512 Set 13: Design of Classes Circle Class Shape’s draw_lines() is not appropriate for a circle; it needs its own 30 struct Circle : Shape { private: int r; // radius public: Circle(Point p, int rr) : r(rr) { // store radius add(Point(p.x-r,p.y-r)); // store center point } void draw_lines() const; // uses FLTK to draw circle /* get and set radius */ };

31 CSCE 121:509-512 Set 13: Design of Classes Polygon Class To draw a (closed) polygon, connect all the points in series, and then connect last point to first point So Polygon’s draw_lines could – call Shape::draw_lines() to connect all the points – then use FLTK directly to draw a line from last point to first point 31

32 CSCE 121:509-512 Set 13: Design of Classes Virtual Functions Sometimes we’d like functions in a class hierarchy to behave in a flexible way, as in draw_lines examples A function in a base class B can be declared as virtual. This function can then be overridden in a derived class D (or any descendant class). The overriding function must have exactly the same signature as in the base class but can have different code in its body The overriding function in the derived class can access versions of the function in ancestor classes using :: 32

33 CSCE 121:509-512 Set 13: Design of Classes “Exactly the Same Signature” struct B { void f1(); // not virtual virtual void f2(char); virtual void f3(char) const; virtual void f4(int); }; struct D : B { void f1(); // doesn’t override void f2(int); // doesn’t override void f3(char); // doesn’t override void f4(int); // overrides 33

34 CSCE 121:509-512 Set 13: Design of Classes Virtual Function Example 34 struct B { virtual void f() { cout << “B::f” << endl; }; struct D : B { void f() { // if desired, you can refer to B::f() in here cout << “D::f” << endl; }; int main() { D d; d.f(); // prints out “D::f” }

35 CSCE 121:509-512 Set 13: Design of Classes Using Virtual Functions Virtual functions are useful if you have a function with an argument that is a base class reference (or pointer) and you want to pass in an argument that is an object of the base class or of a derived class 35 void work(B& b) { b.f(); } //... B b; work(b); // this call to work executes B::f() D d; work(d); // this call to work executes D::f()

36 CSCE 121:509-512 Set 13: Design of Classes Polymorphism The choice of which version of f to execute is made at RUN-TIME, based on the type of the actual parameter (not the formal parameter). Called run-time polymorphism or dynamic dispatch. Relies on fact that a reference to a base class is “compatible with” a reference to any derived class. 36

37 CSCE 121:509-512 Set 13: Design of Classes Polymorphism in Shape Hierarchy Window class maintains a vector of references (actually pointers) to Shapes – each reference actually refers to an object whose class is derived from Shape (e.g., Rectangle, Circle) – another advantage of inheritance: can have a vector of references to base class, while actual objects are of potentially different derived classes When the window is to be (re)drawn on the screen, go through the Shapes vector, calling draw_lines(); correct version will be executed 37

38 CSCE 121:509-512 Set 13: Design of Classes Polymorphism in Shape Hierarchy draw() is a public function of Shapes and is inherited by all derived classes inside draw() is a call to protected and virtual draw_lines() the system will make sure that the right version of draw_lines is executed, depending on the type of the object pointed to (referred to) by shapes[i] 38 class Window : public Fl_Window { // derived from FLTK private: vector shapes; // vector of ptrs to Shapes /*... */ protected: void draw() { Fl_Window::draw(); // calling parent’s draw function for (int i = 0; i < shapes.size(); ++i) shapes[i]->draw(); // *** polymorphism here *** } /*... */ };

39 CSCE 121:509-512 Set 13: Design of Classes Display Model Completed 39 Circle draw_lines() Text draw_lines() Window Display Engine draw() our code make objects wait_for_button() Shape draw_lines()

40 CSCE 121:509-512 Set 13: Design of Classes Pure Virtual Functions Sometimes a function in an interface cannot be implemented – Perhaps the data needed only exists in the derived class(es) We must ensure that every derived class implements that function Method is to make the function “pure virtual”: virtual double f(int i) = 0; This is how to define truly abstract interfaces 40

41 CSCE 121:509-512 Set 13: Design of Classes Revisiting Benefits of Inheritance Interface inheritance: – A function expecting a (reference to a) Shape can accept any object of a class derived from Shape – Simplifies use – We can add classes derived from Shape without rewriting user code Implementation inheritance: – Simplifies implementation of derived classes – Common functionality can be provided in one place – Changes can be done in one place and have universal effect 41

42 CSCE 121:509-512 Set 13: Design of Classes Object-Oriented Programming OOP = inheritance + polymorphism + encapsulation Inheritance: based and derived classes struct Circle : Shape { /*... */ }; Polymorphism: virtual functions virtual void draw_lines() const; Encapsulation: privated and protected protected: Shape(); private: vector points; 42

43 CSCE 121:509-512 Set 13: Design of Classes Code Organization 43 // Graphing interface: struct Shape { … }; … // window interface: class Window {…}; … FLTK headers Graph code Window code FLTK code user-program.cpp: Window.h: Window.cpp: #include "Graph.h" #include "Window.h" int main() { … } Graph.cpp: Graph.h: struct Point { … }; // GUI interface: struct In_box { … }; … GUI code GUI.cpp: GUI.h: Point.h:

44 CSCE 121:509-512 Set 13: Design of Classes Source Files Header files (.h): – Contain interface information (declarations) – Need to be #included by both user and implementer Implementation code files (.cpp): – Contain code implementing interfaces specified in header files – #include the header files User code files (.cpp): – Contain code using the graphics/GUI facilities – #include the header files Read Graph.h (and later Graph.cpp) – Window.h and Window.cpp make heavy use of yet unexplained C++ features 44

45 CSCE 121:509-512 Set 13: Design of Classes Acknowledgments Slides are based on those for the textbook: http://www.stroustrup.com/Programming/13_graph_classes.ppt http://www.stroustrup.com/Programming/14_class_design.ppt 45


Download ppt "CSCE 121:509-512 Introduction to Program Design and Concepts Dr. J. Michael Moore Spring 2015 Set 13: Design of Classes CSCE 121-200: Set 13: Design of."

Similar presentations


Ads by Google