FAQ 8.08 Should Circle inherit from Ellipse ?

FAQ 8.08 Should Circle inherit from Ellipse?

The answer depends on what class Ellipse promises to do. Circle can be substitutable for Ellipse only if Circle supports all of the member functions defined by Ellipse.

Suppose Ellipse has a setSize(x,y) member function that sets the width and height of the Ellipse.

 #include <iostream> using namespace std; class Ellipse { public:   Ellipse(float width, float height) throw();     // PROMISE: width() will return the same as parameter     // width     // PROMISE: height() will return the same as parameter     // height   virtual ~Ellipse() throw();   virtual void setSize(float width, float height) throw();     // PROMISE: width() will return the same as parameter     // width     // PROMISE: height() will return the same as parameter     // height   float width() const throw();   float height() const throw(); protected:   float width_, height_; }; Ellipse::Ellipse(float width, float height) throw() : width_(width) , height_(height) { } Ellipse::~Ellipse() throw() { } void Ellipse::setSize(float width, float height) throw() {   width_ = width;   height_ = height; } float Ellipse::width() const throw() { return width_; } float Ellipse::height() const throw() { return height_; } 

Now suppose someone uses an Ellipse and sets its width to 10 and its height to 20:

 void sample(Ellipse& ellipse) {   // Set the dimensions of the Ellipse to 10 x 20   ellipse.setSize(10, 20);   // Legitimately rely on the promises made by Ellipse:   if (ellipse.width() != 10 || ellipse.height() != 20)     cerr << "Error! Call the hotline at 1-800-BAD-BUGS\n"; } 

In this case, a derived class called Circle would not be substitutable for Ellipse because Circle (presumably) cannot be resized asymmetrically.

 class Circle : public Ellipse { public:   Circle(float initRadius) throw();     // PROMISE: width() will equal initRadius,     // height() will equal initRadius   // But what should we do with setSize(float x, float y); ? }; Circle::Circle(float initRadius) throw() : Ellipse(initRadius, initRadius) { } 

For example, if someone legitimately passed a Circle in to function sample(), then the Circle would get deformed so it is no longer circular:

 int main() {   Circle c(10);   cout << "initial Circle dimensions = "        << c.width() << "x" << c.height() << "\n";   sample(c);   cout << "final Circle dimensions = "        << c.width() << "x" << c.height() << '\n"; } 

The output of this program is

 initial Circle dimensions: 10x10 final Circle dimensions: 10x20 

A 10 x 20 circle is a strange-looking circle!

The lesson is that proper inheritance is based on substitutable behavior.



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net