Re: Never ever use a raw pointer when a smart pointer can do the
same job
* Noah Roberts:
Alf P. Steinbach wrote:
* Noah Roberts:
Alf P. Steinbach wrote:
* Noah Roberts:
and there's the other case when you don't care but sometime down
the road someone decides that a subclass should be returned rather
than the one you're constructing.
You don't. That's totally evil. You're *changing the behavior*
without changing the type, leaving client code stranded with
mysterious behavior change.
That's only true if one of two things is true:
* Your client code is depending on the private behavior of the class
instead of the advertised pre/post conditions.
* Your new sub object violates the advertized pre/post conditions of
the class it inherits from.
If the new class changes nothing wrt. client code, then there is
absolutely no reason to foist a replacement on the client code.
I thought you'd understand that from my comments, but I wasn't clear
enough.
So let me put it this way: *either* the new class is different in some
way that affects behavior, in which case you're changing the behavior,
or else it's not, in which case it's not very smart to do a lot of
work to replace the original.
Sounds to me like maybe your classes depend too much on HOW things do
something rather than that they do. A stack drawing client doesn't care
how the items in the stack draw, it only cares that they do. The drawn
objects don't care how the stack drawing client decides to draw them,
and in fact probably don't even know they're in a stack at all. A hit
check algorithm doesn't care how the objects it's checking give it a
boundary polygon, only that they do and that this polygon represents the
boundaries of the object in question; the objects returning the polygon
do not care or know how the hit check algorithm works, only that it
needs a polygon.
All clients should be thus.
This is the essence of OOP: you can change the behavior of your
application by extending the objects that implement it without having to
make sweeping changes across the whole codebase. It's also the core
reason behind the most important principle of OOP: the open/closed. This
is done by making sure objects are not irresponsibly coupled to each
other, INCLUDING (most importantly probably) that client code is not
coupled to the implementation details behind an interface.
This is the core of encapsulation.
Once again, I'm quite surprised at your argument. This is back to the
basics stuff.
It doesn't seem that you understood it.
But let's take your first example, the stack.
You're saying a factory function is nice because it allows you to change the
stack representation without updating the clients.
If (A) the new stack class doesn't change anything wrt. the client code, then
it's just so much waste.
If it does change something, e.g. allowing *new* client code to use some extra
features or whatever, then either (B) it conforms to the old interface, in which
case the original class should just be replaced with the new one (and no need
for a factory function to do that), or else (C) it doesn't conform to the old
interface, in which case it absolutely shouldn't be foisted on old client code.
I'd be surprised if you can think of a case I haven't enumerated here.
But perhaps you can, I always try to be open-minded. ;-)
Cheers & hth.,
- Alf