473,756 Members | 1,808 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Rectangle: struct or class?

The following may strike many of you as just plain silly, but it represents
the kind of delelima I find myself in when trying to make a design
decision. This really is a toy project written for the purpose of learning
to work with C++. It therefore makes some sense for me to give the
situation the amount of consideration presented below. To be quite honest,
I'm amazed at the amount there is to say about such a seemingly simple
situation.

I'm trying to learn to use C++ the way Stroustrup tells us to in TC++(PL).
He has a few different guidelines for determining if something should be
treated as a class or a struct (in the 'C' sense). One measure is whether
it has an invariant that needs to be preserved. So, say I have a rectangle
{x,y,w,h} where x and y are the coordinates of the top left corner, and w
and h are width and height respectively. I can arbitrarily change any
element of that set and still have a rectangle (assuming w > 0, h > 0, or I
assign meaning to the alternatives). Another criteria he has is whether
there are two possible representations of the same abstraction. If so, it
argues that it should be a class To that I say yes.

struct Rectangle{size_ t x, y, w, h;};
struct Point{size_t x,y;};
struct RectanglePts{Po int xy, dxdy;}

I may also want some convenience functions such as

Rectangle& Rectangle::wide n(const size_t dw){ this->w += dw; return this; }
Rectangle& Rectangle::move (const Point dxy){
this->x += dxy.x;
this->y += dxy.y;
return this; }

Interestingly, there is an operation for which when an invariant can be
identified. The displacement between Rectangle::xy and Rectangle::dxdy
should be preserved under translations. Likewise scale operations should
preserve the ratio between the lengths of the sides.

Then I ask if Rectangle should derive from Point. There are arguments for
either choice. He suggests asking the question "can the object have two of
the things you are considering as a base class". At first I might say
"yes", I can have more than two points. I only need two points to define
the rectangle. That argues that the Rectangle should have Point members,
rather than be a Point. But what if we say a point isn't just a point,
it's a location. So we ask again, "can it have two?". Well, yes and no.
It can have many locations within it. Mathematically, there are an
infinite number of points in a rectangle. But the rectangle as a whole
only realistically has one position.

And it makes some sense to treat the rectangle as a position with a size and
shape. Rather than thinking of a Point as a pair of coordinates, or a
location, we might think of it as a geometric object. It could be
considered as the fundamental geometric object. We will never draw a
geometric object on a screen without it having a location. I can use the
same set of operations to move any geometric object, as I use to move a
point. I might even write some operators to add two points as vectors, and
then inherit these in other geometric objects. If I add a Point to a
rectangle it is equivalent to moving the rectangel such that the
coordinates of the top left corner have the components of the point added
to them.

I have not completely definitive test to determine whether a rectangle
should be a class or a struct. Nor can I clearly decide if it should be a
Point and have another Point, or if it should have two points. I favor the
former for the reasons involving positioning.

But now, I have to consider a point. Can it have two representations ? A
stupid {x,y} odered pair? Yup! {r cos(theta), r sin(theta)}. I even
briefly entertained the idea of inheriting from std::complex to get my
Point class.

But is it a class? It doesn't seem to have any other invariant than "it has
two components". But that /is/ an invariant that is determined when the
object is created. But that is true of any struct with two members.

So what's the advantage of protecting the components of Point? One argument
people give is that it prevents me from inadvertently modifying the data.
That seems a bit spurious to me in this case. Another, more reasonable
argument that Stroustrup doesn't mention is the notion of event
notification. If I change a value on Point, I may want to notify the
graphics rendering software of the change so it can schedule an update. If
I call a method to make the change, I can have the event fired as a side
effect.

So I make the components protected. So what? What dose that cost me? The
Point that I inherit in Rectangle acts just the way I want it. It inherits
everything from point that I need it to. OTOH, when I try to modify the
components of the lower right corner dxdy, I find I am not permitted to
access the protected data. So, either I use the public interface to modify
the data, or make Rectangle or some standalone function a friend of Point.
The former is a cyclic reference, and bad design, as a general rule. The
latter is something I find to be in bad taste.

If my public interface to point is well designed, writing that bit of extra
code within Rectangle is no big deal. There is one last factor I would
consider, and I honestly don't know what the answer is. Does a decent
compiler (g++, in my case) optimize away the function calls such as:

Point<T>& operator+=(cons t Point& p)
{
this->x += p.x;
this->y += p.y;
return *this;
}
?
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05
15 9074
Steven T. Hatton wrote:
Kai-Uwe Bux wrote:
Steven T. Hatton wrote: [...]

Hi,
this LSP seems to be a convoluted way of the following test: Ask
yourself, is every rectangle a point? This is clearly not the case. Thus,
do not derive Rectangle from Point.

It appears that classes and inheritance are a good way to map the
ontology of your problem domain in an intuitive way to the type
structure/hierarchy of your code. A class D derived from B has all
members of B but may add more information and more methods. It is
therefore more special. The assignement

B b;
D d;
b = d;


But you are slicing there.


What is slicing? I am just pointing out that the syntax of C++ clearly
indicates that every D is a B but not vice versa.

I believe a more realistic test would be can I do:

Rectangle r.

void f(Point& p){...}
You are using a reference? In C++, you should base the decision whether to
derive or upon how this decision fits within the semantics of the language
as a whole. Assignments like b = d are legal, and f(Point p) can be called
on rectangles, too.
f(r);

and get reasonable results when functions from Point are invoked on
Rectangle? And the answer is yes. Every function from Point in Rectangle
other than

ostream& Point::stringif y(ostream& out)

behaves exactly as it does when called on a Point object.

That just indicates that your Points are not really full fledged points.
Clearly you are missing a lot of possible methods that would make a
difference. What about, for instance, a method p.draw()?
Sure there are. I can translate a rectangle r1 by doing r1 += p1.


So what? Every shape can be translated.


So every shape is derivable from Point.

Yes, so if Rectangle inherits from Point all rectangles should be
degenerate. Assume Rectangle inherits from Point. Consider

Rectangle r ( ... ); // initialize a unit square
Point p;

p = r;
std::cout << r.Area() << " = " << p.Area() << " ?\n" << std::cout;

Methods that make sense for the base class should not without very good
reason completely change the meaning in derived classes.


Well, I didn't put an area function on Point, but it could easily be done
with meaning. Area == 0; I might have considered making it pure virtual,
but that would make Point pure virtual, and I have a use for instantiating
Point, and a reasonalbe return value for the area of a point.


Now, I think the whole problem is that you named the base class Point in a
bad way: it should have been called LocatedShape or something like this.
You are using the two coordinates of your Point class only for the
reference point indicating the location of classes derived from Point. The
name Point, however, suggests that the class would allow for methods like
Area() or draw(), which clearly yield absurd results.

In short, that these methods are missing, tells me that your Point class is
more general than a Point class should be. There is nothing wrong with
inheriting BasepointedRect angle (given by lower left corner, width, height
) from something like BasepointedShap e (given by x and y coordinates) and
AbstractRectang le (width and height only).

The real question is how you want to map the ontology of your problem
domain into your code. And questions about ontological relations are of the
type is every D a B?
Best

Kai-Uwe Bux
Jul 22 '05 #11


Steven T. Hatton wrote:


I don't believe the argument you presented follows from that principle.

If S is Rectangle, and T is Circle, an instance o1 of Rectangle is not
interchangeable with an o2 that is an instance of Circle. Circle is not a
subtype of rectangle. But I didn't intend it to be. There /are/ graphics
programs that do derive all shapes from rectangle. In such cases, the
Rectangle is a bounding rectangle of the given shape.

Of course you can't substitute a rectangle for a circle or a circle for
a rectangle, but you can substitute a rectangle for a shape and a circle
for a shape. Both rectangle and circle are S of T (shape).
I find the LSP to be a formal statement of the obvious.

There are arguments for either choice.
In this case I'd say there's almost no reasonable argument for
inheritance .

Sure there are. I can translate a rectangle r1 by doing r1 += p1.


You can't translate anything by a point. You can translate it by a
vector, but a point isn't a vector. Whilst you can 'release' a point to
create a vector, or 'anchor' a vector to create a point, the two things
are not the same.


The degenerate case of geometric object is point.


Hmm I tried that argument on my mathematicians a couple of years ago,
when I wanted to treat a degenerate curve as a point. I was beaten up
something horrid, I recall the most favourably description of the scheme
was that it was a 'bastardization '.
Jul 22 '05 #12
In article <JO************ ********@speake asy.net>,
"Steven T. Hatton" <su******@setid ava.kushan.aa> wrote:
Daniel T. wrote:
In article <Me************ ********@speake asy.net>,
"Steven T. Hatton" <su******@setid ava.kushan.aa> wrote:
...
Another criteria he has is whether
there are two possible representations of the same abstraction. If so, it
argues that it should be a class To that I say yes.

struct Rectangle{size_ t x, y, w, h;};
struct Point{size_t x,y;};
struct RectanglePts{Po int xy, dxdy;}


There are others:

struct Rectangle { int top, left, bottom, right; };
struct Rectangle { Point center; int height, width; };
struct Rectangle { Point top_left, bot_right; };

As is plain to see. There are many different representations of
Rectangle.


I'm not sure if the number of possible representations argues more strongly
for use of class over struct. I'll have to give that further
consideration.


I thought you already were. From your OP:
I'm trying to learn to use C++ the way Stroustrup tells us to in TC++(PL).
He has a few different guidelines for determining if something should be
treated as a class or a struct (in the 'C' sense). One measure is whether
it has an invariant that needs to be preserved. So, say I have a rectangle
{x,y,w,h} where x and y are the coordinates of the top left corner, and w
and h are width and height respectively. I can arbitrarily change any
element of that set and still have a rectangle (assuming w > 0, h > 0, or I
assign meaning to the alternatives). Another criteria he has is whether
there are two possible representations of the same abstraction.
As you rightly point out above, Stroustrup believes that multiple
representations mean we should use a class. I'm pointing out that there
are multiple representations ...

I may also want some convenience functions such as

Rectangle& Rectangle::wide n(const size_t dw){ this->w += dw; return this;
} Rectangle& Rectangle::move (const Point dxy){
this->x += dxy.x;
this->y += dxy.y;
return this; }

Interestingly, there is an operation for which when an invariant can be
identified. The displacement between Rectangle::xy and Rectangle::dxdy
should be preserved under translations. Likewise scale operations should
preserve the ratio between the lengths of the sides.


class Rectangle {
public:
double area() const;
int top() const;
int left() const;
int bottom() const;
int right() const;
Point top_left() const;
Point top_right() const;
Point bot_left() const;
Point bot_right() const;
// many others...
};

There are many invariants that must be maintained among the above
methods. Notice, I haven't expressed any particular representation. ..


I have to ask how many of these invariants are 'orthogonal'. Which can be
derived from the other.


It doesn't matter. All of the methods above represent properties of a
Rectangle and there are definite invariants that exist between some of
them.

To some extend, the is a question of how much work
I want my rectangle class to do for the user.
The answer to that should be "all the rectangle work".

Then I ask if Rectangle should derive from Point. There are arguments
for
either choice. He suggests asking the question "can the object have two
of
the things you are considering as a base class". At first I might say
"yes", I can have more than two points. I only need two points to define
the rectangle. That argues that the Rectangle should have Point members,
rather than be a Point. But what if we say a point isn't just a point,
it's a location. So we ask again, "can it have two?". Well, yes and no.
It can have many locations within it. Mathematically, there are an
infinite number of points in a rectangle. But the rectangle as a whole
only realistically has one position.


Yes, a nice point.

void move( IT begin, IT end ) {
while ( begin != end ) {
begin->move_right( 5 );
++begin;
}
}


There are arguments for using member functions to perform the actual
manipulation, or using external 'helper' functions to manipulate the
objects.


Absolutly, and for class that have no virtual functions there is little
difference...

Rect { int x, y, h, w };

void move( Rect& r, int dx, int dy ) {
r.x += dx;
r.y += dy;
}

isn't much different than:

class Rect {
int x, y, h, w;
public:
void move( int dx, int dy ) {
x += dx;
y += dy;
}
};

Except that with the latter, you can more esily change the 'int x, y, h,
w' to (for example) 'int top, left, bottom, right'.

There is no reason why the above function should only work on Points, it
could just as easily work on Rectangles, Circles, &c. What do all these
things that the move function can act on have in common? If you had to
use one word to describe them all, would you use "Point"? I think not...


I would use "position".


Position (n): the point or area occupied by a physical object.

Is the "point or area occupied by a physical object" synonymous to/a
generalization of "Rectangle" ? I don't think so.

For
example, what do I want to choose as the definitive point when I talk about
position.
Certanly the 'move' function we are describing doesn't care.

Stroustrup tells us it is probably a good idea to separate our code from any
dependencies on specific third party libraries, as much as possible. See
the various discussions in Chapter 12 of TC++PL(SE).
I would say the best way to do this is the following. (a) find two third
party libraries that have the functionality needed (b) write your code
in such a way that you can switch from one library to the other with the
fewest changes.

Taking that approach,
I want to identify the abstract essentials of what a rectangle means to me.
My approach is this:

I want to be able to set, and get the color of the rectangle, change some
text displayed in the rectangle, establish the size and position of the
rectangle, and, of course construct and destroy the rectangle. Caveat
emptor on this last operation. Someone else may own it.


class Rectangle {
// private stuff
public:
void setColor( const Color& c );
const Color getColor() const;
void changeText( const std::string& s );
void setCenterPostio n( const Point& p );
void setSize( unsigned width, unsigned height );
};

the above class does everything you need, but says nothing to the
outside world about what its internal representation is. The internal
representation could be any of the 6 we discussed at the top of this
post or something different.
Jul 22 '05 #13
Steven T. Hatton wrote:
Jerry Coffin wrote:

"Steven T. Hatton" <su******@setid ava.kushan.aa> wrote in message
news:<Me***** *************** @speakeasy.net> ...

[ ... ]

Then I ask if Rectangle should derive from Point.


I suggest asking the question: "does this derivation satisfy the
Liskov Substitution Principle?" To wit, is it reasonable to substitute
a rectangle for a point under all possible circumstances? The answer
is clearly no: for example, saying a 2x3 unit rectangle is the center
of a 1 unit circle simply makes no sense.

I don't follow the reasoning here. Suppose I have a class called Shape which
holds data relevant to all shapes in my program, e.g., color, position,
velocity, display state, etc. It would make sense to derive Rectangle from
that, if I am actually talking about a displayed graphical rectangle. It
would also make sense to derive Circle from the same base class. But this
derivation would fail this substitution test as well. I've never heard of
the Liskov Substitution Principle, but google turned this up:


Mathematically, a point has no area. A rectangle has an area.

One can draw a line between two points. In drawing a line between
two rectangles, where does one connect the lines?

One can calculate a distance between two points. How does one calculate
the distance between two non-collinear rectangles?

Although one could _use_ a rectangle to represent a point, you have
a circular reference. If a rectangle is represented by four points,
and yet is a point, where does it end?

You should consider that an implementation of a rectangle contains
points, it is _not_ a point. The phrase is simplified to a
rectangle "has-a" point. The "has-a" relationship is a very good
indicator of containment versus the "is-a" relationship for
inheritance.

The C++ FAQ has a good discussion about circles, elipses inheritance
and containment.

Also, just because a rectangle can be a point[1] does not mean it
should be one.

----
[1] Many computer systems draw lines using rectangles. As the line
of rectangles is viewed from a far distance, it looks like a
a line. Rectangles _can_ be used as points.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.l earn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 22 '05 #14
"Steven T. Hatton" <su******@setid ava.kushan.aa> wrote in message news:<Fv******* *************@s peakeasy.net>.. .

[ ... ]
I don't follow the reasoning here. Suppose I have a class called Shape which
holds data relevant to all shapes in my program, e.g., color, position,
velocity, display state, etc. It would make sense to derive Rectangle from
that, if I am actually talking about a displayed graphical rectangle. It
would also make sense to derive Circle from the same base class. But this
derivation would fail this substitution test as well.
Unless you define your Shape class very oddly, this design would pass
the substitution test perfectly -- in fact, it's pretty much what I
suggested.
I've never heard of
the Liskov Substitution Principle, but google turned this up:
I'd do some more looking, and read about it in more detail. For most
practical purposes, it's the single principle that guides all use of
derivation.
http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple

"What is wanted here is something like the following substitution property:
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 behavior of P is unchanged
when o1 is substituted for o2 then S is a subtype of T."

I don't believe the argument you presented follows from that principle.
Whoever wrote that definition seems to have specialized in
obfuscation, but from a practical viewpoint, following the LSP means
that you can substitute a derived object for a base object under any
possible circumstances.
If S is Rectangle, and T is Circle, an instance o1 of Rectangle is not
interchangeable with an o2 that is an instance of Circle. Circle is not a
subtype of rectangle. But I didn't intend it to be. There /are/ graphics
programs that do derive all shapes from rectangle. In such cases, the
Rectangle is a bounding rectangle of the given shape.
There are many examples of truly horrible designs in the world. That
doesn't make it a good idea to add another.
I find the LSP to be a formal statement of the obvious.
In that case you're advocating designs that obviously wrong.
Sure there are. I can translate a rectangle r1 by doing r1 += p1.
IMO, you seem to be progressing from bad to worse. Adding a point to a
polygon should do exactly that: add a point to the polygon, normally
resulting in a polygon with one more vertex.
The degenerate case of geometric object is point.
Degenerate cases rarely mean much, at least when you're talking about
derivation. It's true (for example) that a rectangle with sides of
length 0 is really a single point, an example proving your point above
valid. That means that a rectangle CAN be a point (as can a circle,
etc.) To be meaningful from a viewpoint of derivation, however, you
have to show that EVERY rectangle is a point, every circle is a point,
etc.

That's not the case, and a hierarchy that assumes it is will cause
almost nothing but problems.

Keep in mind that in the end there are two basic ideas here: we want
the compiler to allow the things that make sense, but disallow (short
of things like casting to force it to allow them) things that don't
really make sense.

The question, then, is whether you want to be able to pass a
rectangle, circle, etc., to every function, every place, that a point
is accepted. Regardless of what you think that's what the LSP states,
that IS what the compiler allows: if I have code like this:

class base {};
class derived : public base {};

void func(const base &b) {
}

then I can pass an instance of derived to func without any casting,
etc. I.e. the compiler assumes that when I use derivation, that I mean
the derived object can be substituted for the base class object.

[ ... ]
I could even derive a Circle from a Rectangle by imposing the restriciton
that the sides be invariantly equal, and defining the center as the bottom
right point.
You _could_ do almost anything -- but what you're advocating here will
lead to NOTHING but problems.
Stroustrup argues that an elipse should not be derived from a circle because
an elipse is defined by two foci, and a circle just happens to be the
degenerate case where the foci cooincide. Well that is not the only way to
describe an elipse. You /can/ draw an elipse by using a radial vector
placed at the origin. So I can also derive an Elipse fromm my Rectangle,
and might even derive a Circle from the Elipse.
Deriving circle from ellipse is almost always a bad idea. Public
derivation means that the derived class has the full interface of the
base class. In the case of an ellipse base class, you're typically
going to have some way of setting the major and minor axes to
different values. If circle derives from ellipse, it's promising to do
the same -- but doing so would give an ellipse instead of a circle.

The bottom line: from a viewpoint of substitutabilit y, a circle is not
an ellipse and an ellipse is not a circle. Any attempt at deriving one
from the other will normally result in problems.

[ ... ]
In §23.4.7 of TC++PL(SE) Stroustrup tells us "Donald Knuth observed that
'premature optimization is the root of all evil.' Some people have learned
that lesson all too well and condider all concern for efficiency evil. On
the contrary, efficiency must be kept in mind throughout the design and
implementation effort."
Good for him. In this case, he's mostly wrong. The fact is that most
people who try to take efficiency into account early in the design end
up causing themselves problems. First of all, they're usually wrong
about what to optimize, so even at best their attempt does no good.
Second, in their zeal for optimizing the wrong things, they exacerbate
the real problem. Finally, they typically make the interface too low
of level, so it's almost impossible to hide the complex parts
internally, so the real performance problems become difficult to fix.
In the case of complex simulations, it's a good idea to be sure you don't
put inheritnly inefficient code at the foundation.
Regardless of the type of program, there's no point in introducing
needless inefficiency. Nonetheless, if you start with a good
algorithm, express it cleanly, and provide a clean interface, chances
are roughly 99% that your code will not only be fast enough, but that
it'll be faster than most of the other code out that that was
"optimized" much more carefully.

[ ... ]
For example, Stroustup tells us that traversing a linked list
using a for loop is much more efficient than using recursion.

There are many instances in which I like to use recursion. That knowledge
is certain to have an impact on my future design decisions.


My advice would be simpler: use recursion when it improves readability
and understandabili ty, but not otherwise. Certainly, use iteration to
walk a linked list, but do it because it's more understandable. If
you're coding a tree traversal, it's rarely worthwhile to do it
iteratively -- and when it is, it's NOT a question of recursion vs.
iteration per se. It's (for example) when you're talking a directory
tree, and recursion gives you a depth-first traversal which is
generally substantially slower than a width-first traversal, which
happens to be easier to to iteratively.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 22 '05 #15
"Steven T. Hatton" <su******@setid ava.kushan.aa> wrote in message news:<Fv******* *************@s peakeasy.net>.. .

[ ... ]
I don't follow the reasoning here. Suppose I have a class called Shape which
holds data relevant to all shapes in my program, e.g., color, position,
velocity, display state, etc. It would make sense to derive Rectangle from
that, if I am actually talking about a displayed graphical rectangle. It
would also make sense to derive Circle from the same base class. But this
derivation would fail this substitution test as well.
Unless you define your Shape class very oddly, this design would pass
the substitution test perfectly -- in fact, it's pretty much what I
suggested.
I've never heard of
the Liskov Substitution Principle, but google turned this up:
I'd do some more looking, and read about it in more detail. For most
practical purposes, it's the single principle that guides all use of
derivation.
http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple

"What is wanted here is something like the following substitution property:
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 behavior of P is unchanged
when o1 is substituted for o2 then S is a subtype of T."

I don't believe the argument you presented follows from that principle.
Whoever wrote that definition seems to have specialized in
obfuscation, but from a practical viewpoint, following the LSP means
that you can substitute a derived object for a base object under any
possible circumstances.
If S is Rectangle, and T is Circle, an instance o1 of Rectangle is not
interchangeable with an o2 that is an instance of Circle. Circle is not a
subtype of rectangle. But I didn't intend it to be. There /are/ graphics
programs that do derive all shapes from rectangle. In such cases, the
Rectangle is a bounding rectangle of the given shape.
There are many examples of truly horrible designs in the world. That
doesn't make it a good idea to add another.
I find the LSP to be a formal statement of the obvious.
In that case you're advocating designs that obviously wrong.
Sure there are. I can translate a rectangle r1 by doing r1 += p1.
IMO, you seem to be progressing from bad to worse. Adding a point to a
polygon should do exactly that: add a point to the polygon, normally
resulting in a polygon with one more vertex.
The degenerate case of geometric object is point.
Degenerate cases rarely mean much, at least when you're talking about
derivation. It's true (for example) that a rectangle with sides of
length 0 is really a single point, an example proving your point above
valid. That means that a rectangle CAN be a point (as can a circle,
etc.) To be meaningful from a viewpoint of derivation, however, you
have to show that EVERY rectangle is a point, every circle is a point,
etc.

That's not the case, and a hierarchy that assumes it is will cause
almost nothing but problems.

Keep in mind that in the end there are two basic ideas here: we want
the compiler to allow the things that make sense, but disallow (short
of things like casting to force it to allow them) things that don't
really make sense.

The question, then, is whether you want to be able to pass a
rectangle, circle, etc., to every function, every place, that a point
is accepted. Regardless of what you think that's what the LSP states,
that IS what the compiler allows: if I have code like this:

class base {};
class derived : public base {};

void func(const base &b) {
}

then I can pass an instance of derived to func without any casting,
etc. I.e. the compiler assumes that when I use derivation, that I mean
the derived object can be substituted for the base class object.

[ ... ]
I could even derive a Circle from a Rectangle by imposing the restriciton
that the sides be invariantly equal, and defining the center as the bottom
right point.
You _could_ do almost anything -- but what you're advocating here will
lead to NOTHING but problems.
Stroustrup argues that an elipse should not be derived from a circle because
an elipse is defined by two foci, and a circle just happens to be the
degenerate case where the foci cooincide. Well that is not the only way to
describe an elipse. You /can/ draw an elipse by using a radial vector
placed at the origin. So I can also derive an Elipse fromm my Rectangle,
and might even derive a Circle from the Elipse.
Deriving circle from ellipse is almost always a bad idea. Public
derivation means that the derived class has the full interface of the
base class. In the case of an ellipse base class, you're typically
going to have some way of setting the major and minor axes to
different values. If circle derives from ellipse, it's promising to do
the same -- but doing so would give an ellipse instead of a circle.

The bottom line: from a viewpoint of substitutabilit y, a circle is not
an ellipse and an ellipse is not a circle. Any attempt at deriving one
from the other will normally result in problems.

[ ... ]
In §23.4.7 of TC++PL(SE) Stroustrup tells us "Donald Knuth observed that
'premature optimization is the root of all evil.' Some people have learned
that lesson all too well and condider all concern for efficiency evil. On
the contrary, efficiency must be kept in mind throughout the design and
implementation effort."
Good for him. In this case, he's mostly wrong. The fact is that most
people who try to take efficiency into account early in the design end
up causing themselves problems. First of all, they're usually wrong
about what to optimize, so even at best their attempt does no good.
Second, in their zeal for optimizing the wrong things, they exacerbate
the real problem. Finally, they typically make the interface too low
of level, so it's almost impossible to hide the complex parts
internally, so the real performance problems become difficult to fix.
In the case of complex simulations, it's a good idea to be sure you don't
put inheritnly inefficient code at the foundation.
Regardless of the type of program, there's no point in introducing
needless inefficiency. Nonetheless, if you start with a good
algorithm, express it cleanly, and provide a clean interface, chances
are roughly 99% that your code will not only be fast enough, but that
it'll be faster than most of the other code out that that was
"optimized" much more carefully.

[ ... ]
For example, Stroustup tells us that traversing a linked list
using a for loop is much more efficient than using recursion.

There are many instances in which I like to use recursion. That knowledge
is certain to have an impact on my future design decisions.


My advice would be simpler: use recursion when it improves readability
and understandabili ty, but not otherwise. Certainly, use iteration to
walk a linked list, but do it because it's more understandable. If
you're coding a tree traversal, it's rarely worthwhile to do it
iteratively -- and when it is, it's NOT a question of recursion vs.
iteration per se. It's (for example) when you're talking a directory
tree, and recursion gives you a depth-first traversal which is
generally substantially slower than a width-first traversal, which
happens to be easier to to iteratively.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 22 '05 #16

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1506
by: AsuWoo | last post by:
you are given two rectangles, each defined by an upper left(UL) corner and a low right(LR)corner,Both rectangles' edges will always be parrallel to the x or y axis ,Write a window program with c# that user can use mouse to draw the rectangle add the program will determines whether the two rectangles overlap. For convenience, you may use the following structs: Struct point{ Int x; Int y; } Struct rect{
5
1793
by: woodBeeProgrammer | last post by:
this is a repost of a languishing query. is there a conventional value for "NAR" (Not A Rectangle) that Rectangle may be initialized to, sort of like NAN for doubles? Thanks in advance!!
4
2670
by: Colin McGuire | last post by:
Hi, this is a really simple question I have been banging my head on a brick wall over. The program below changes the background colour of a form depending on whether the cursor is inside a rectangle drawn on the form or not. It works perfectly as shown below. But it won't work if I change the values of scaleFactor, rotateFactor, translateFactorX, translateFactorY in the program. I would like to 'correct' the values of e.X and e.Y in...
6
23057
by: Mythran | last post by:
I have a question regarding the RECT structure required for PInvoke calls. I was reviewing the Rectangle structure (System.Drawing.Rectangle) and it occurred to me that I may be able to use this structure in place of defining a RECT structure. I would create the RECT structure definition the same as the Rectangle structure is defined. Is there any problems with using Rectangle in place of RECT for the API functions? Thanks, Mythran
5
7632
by: moondaddy | last post by:
I want to create a custom UI element which will be a custom rectangle object in a c# XAML application. I'm new to XAML and c# as most of my experience has been using vb with sql. I'm building a simple Visio type app where I can drag rectangles on a canvas to create diagrams. for now I don't need fancy shapes so I'll just start with a rectangle class where I can add custom properties to it such as where lines are connected to it, etc. ...
7
9431
by: Florian Haag | last post by:
Hello, I'm trying to compile a programme which compiles fine under Linux; I'm trying it with MinGW G++ 3.4.2: Component.h: #ifndef COMPONENT_H_ #define COMPONENT_H_
2
3520
by: John | last post by:
Hi there, I need to create a rectangle between two points so that I can check what is inside it using Contains(). The problem I am having is how to make the rectangle be able to cope with the angle between the two points, see the image in the link for what I mean. http://homepage.ntlworld.com/andrew.baldock/bloodbowl/select.png I am not interested in displaying anything in the rectangle, I just need
1
2881
by: cookiem0n | last post by:
I need to create a class Rectangle. This class stores only the Cartesian coordinates of the four corners of the rectangle. The constructor calls a set method that accepts four sets of coordinates and verifies that each of these is in the first quadrant with no single x- and y- coordinate larger than 20.0. The set method also verifies that the supplied coordinates do, in fact, specify a rectangle. Provide methods to calculate the length, width,...
1
5132
by: kummu4help | last post by:
hi, i want to draw rectangle based on mousedrag event. if user dragging the mouse, then the rectangle on the applet should increase or decrease basing on current mouse coordinates. i have the following code. in the following code i am using SelectionArea class which extends a canvas on which i am performing drawing operation. i am using image variable in this class for double buffering to reduce flickering and to save the applet's previous...
0
9456
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9275
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
9843
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9713
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8713
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7248
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6534
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5304
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2666
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.