Slicing Imagine we have a hierarchy of shape shapes with the following inherits members • get_name(): … circle triangle the name assigned to the shape • get_area(): the area occupied by the shape We also provide swap(&, &) for exchanging two shapes of the same type Let us implement bubble sort Th. Gschwind. Advanced Software Engineering with C++ Templates. 356
Bubble Sort for a vector<shape*> void sort(vector<shape*> &v) { if (v.size() < 2) return ; bool rerun; do { rerun = false; for (size_t i = 0; i < v.size()-1; ++i) { if (v[i]->get_area() > v[i+1]->get_area()) { swap(*v[i], *v[i+1]); rerun = true; } } } while (rerun); } When we invoke swap, we exchange the contents of the shapes at v[i] and v[i+1] To do this, swap(shape&, shape&) is invoked Th. Gschwind. Advanced Software Engineering with C++ Templates. 357
Bubble Sort for a vector<shape*> (cont’d) void swap(shape &s1, shape &s2) { shape t = s1; s1 = s2; s2 = t; } Since the swap function only has space for a shape inside t, only the shape part of s1 is assigned to t Only the shape part of s2 can be assigned to s1 • During runtime s1 and s2 can be objects of different types • It is not possible to assign the contents of a circle to a rectangle Finally, the shape part of t is assigned to s2 Members (i.e., radius, sides a+b+c) used to compute the area of the shape are not swapped Hence, only the name is swapped, and sort will not terminate, because the areas of the shapes are never swapped Th. Gschwind. Advanced Software Engineering with C++ Templates. 358
Bubble Sort for vector<shape*> void sort(vector<shape*> &v) { if (v.size() < 2) return ; bool rerun; do { rerun = false; for (size_t i = 0; i < v.size()-1; ++i) { if (v[i]->get_area() > v[i+1]->get_area()) { swap(v[i], v[i+1]); // swap(*v[i], *v[i+1]); rerun = true; } } } while (rerun); } We should have only exchanged the pointers in the vector Providing swap for shapes, was probably misguided in the first place It makes only sense to swap shapes of the very same type Th. Gschwind. Advanced Software Engineering with C++ Templates. 359
Advanced Software Engineering with C++ Templates Liskov Substitution Principle Thomas Gschwind <thg at zurich dot ibm dot com>
Liskov Substitution Principle Th. Gschwind. Advanced Software Engineering with C++ Templates. 361
Squares and Rectangles I had a colleague who was unsure whether to derive rectangle from square or vice-versa. What would you recommend to him? Implement a set of sample programs illustrating various options and your recommendation! The programs should demonstrate why your solution is better than the other solutions Th. Gschwind. Advanced Software Engineering with C++ Templates. 362
Squares and Rectangles Shape inherits … Line Circle Triangle Class hierarchy for a vector graphics program We have an abstract class Shape from which various geometric shapes are being derived Task: • Add the following classes: Square, Rectangle • Also add useful members like {get,set}_{width,height,length,size }, … Th. Gschwind. Advanced Software Engineering with C++ Templates. 363
Liskov Substitution Principle If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behaviour of P is unchanged when o1 is substituted for o2 then S is a subtype of T. Put Simple: Every function/program must work the same when it is invoked with a subclass instead of the expected class. This is the responsibility of the subclasses! Th. Gschwind. Advanced Software Engineering with C++ Templates. 364
Square Rectangle class Rectangle { int w, h; public : Rectangle virtual void setWidth( int wi) { w=wi; } virtual void setHeight( int he) { h=he; } inherits }; Square class Square : public Rectangle { public : virtual void setWidth( int w) { Rectangle::setHeight(w); Rectangle::setWidth(w); } virtual void setHeight( int h) { setWidth(h); } }; Th. Gschwind. Advanced Software Engineering with C++ Templates. 365
Square Rectangle (cont’d) What happens if we pass a Square to a function test expecting a Rectangle? Can we expect the function test to know about Square? Would it be OK if the function yields an unexpected outcome under the motto garbage-in garbage-out? No! Because we claim that a Square is a Rectangle! void test(Rectangle &r) { Rectangle r.setWidth(5); r.setHeight(4); inherits assert((r.getWidth()*r.getHeight())==20); Square } Th. Gschwind. Advanced Software Engineering with C++ Templates. 366
Square Rectangle V2 class Rectangle { int w, h; public : Rectangle void setWidth( int wi) { w=wi; } void setHeight( int he) { h=he; } inherits }; Square class Square : public Rectangle { public : void setWidth( int w) { Rectangle::setHeight(w); Rectangle::setWidth(w); } void setHeight( int h) { setWidth(h); } }; Th. Gschwind. Advanced Software Engineering with C++ Templates. 367
Square Rectangle V2 (cont’d) What happens if we pass a Square to a function test expecting a Rectangle? The program works now as expected However, since set_width/set_height are no longer virtual our Square is now a Rectangle ==> This is not the solution either void test(Rectangle &r) { Rectangle r.setWidth(5); r.setHeight(4); inherits assert((r.getWidth()*r.getHeight())==20); Square } Th. Gschwind. Advanced Software Engineering with C++ Templates. 368
Rectangle Square Square has one field (height or width) Square Rectangle adds another one for the other dimension inherits • Makes sense from a memory usage point of view Rectangle Square has a method to set the length Rectangle adds methods for height and width • Also makes sense from the methods they provide • A Square does not need set_height & set_width Th. Gschwind. Advanced Software Engineering with C++ Templates. 369
Rectangle Square class Square { Square int l; public : virtual void setLength( int le) { l=le; } inherits virtual int getLength() { return l; } Rectangle }; class Rectangle : public Square { // reuse length as height int w; public : virtual void setLength( int le) { Square::setLength(le); setWidth(le); } virtual void setHeight( int he) { Square::setLength(he); } virtual void setWidth( int wi) { w=wi; } }; Th. Gschwind. Advanced Software Engineering with C++ Templates. 370
Rectangle Square (cont’d) We cannot pass a Square to the test function Square void test(Rectangle &r) { r.setWidth(5); r.setHeight(4); inherits Rectangle assert((r.getWidth()*r.getHeight())==20); } What if test would take Squares? • No problem either, LSP fulfilled void test(Square &s) { s.setLength(5); s.setLength(4); assert((s.getLength()*s.getLength())==16); } Th. Gschwind. Advanced Software Engineering with C++ Templates. 371
Rectangle Square (cont’d) Let us extend our Shape class hierarchy Square Our customer requests a get_area() member int Square::get_area() { return l*l; } inherits int Rectangle::get_area() { return l*wi; } Rectangle void foo(Square &s) { assert((s.get_length()*s.get_length()) ==s.get_area()); } Th. Gschwind. Advanced Software Engineering with C++ Templates. 372
Rectangle Square (cont’d) Let us extend our Shape class hierarchy Square Our customer requests a get_area() member int Square::get_area() { return l*l; } inherits int Rectangle::get_area() { return l*wi; } Rectangle void test(Square &s) { assert((s.get_length()*s.get_length()) ==s.get_area()); } void oh_no_not_another_test() { Rectangle r(3,4); test(r); } Th. Gschwind. Advanced Software Engineering with C++ Templates. 373
Square Shape, Rectangle Shape Shape inherits … Line Circle Square Rectangle Correct, don’t use deep class hierarchies just because it is “object - oriented” programming (is it?) or because it’s “cool” or “professional” (or whatever)! Th. Gschwind. Advanced Software Engineering with C++ Templates. 374
Lessons Learned Avoid code inheritance • People will nail you down on how the base class is implemented If inheritance is needed define an interface • Now, only the documentation counts Inherit the interface not the code If code inheritance is needed, prefer the use of an interface plus use aggregation • Follow this advice especially when using Java • Yes, you need to type a bit more If this is really (really?) not an option provide both an interface and a class to inherit from Th. Gschwind. Advanced Software Engineering with C++ Templates. 375
Advanced Software Engineering with C++ Templates Exceptions Thomas Gschwind <thg at zurich dot ibm dot com>
Exceptions Error Handling Exception Specification Exception Discrimination Cleaning up in C++ (a.k.a. finally ) Standard Exceptions Th. Gschwind. Advanced Software Engineering with C++ Templates. 377
Recommend
More recommend