Re: Why RTTI is considered as a bad design?
On Tuesday, August 21, 2012 6:57:06 AM UTC-7, Scott Lurndal wrote:
=?ISO-8859-1?Q?=D6=F6_Tiib?= <ootiib@hot.ee> writes:
Usually i see dynamic_cast<>() more used for cross-casting rather than d=
own=
-casting. I bring an example. A specific Door passed to SomeDoer::open(D=
oor=
*) may have Lockable interface or not. To have all Doors Lockable by def=
aul=
t would deviate from sane design since most doors can not be locked. Suc=
ces=
s of unlocking may depend of availability of Keys or LockPicks or whatev=
er =
for this SomeDoer so open() forwards these problems to SomeDoer::unlock=
(Lo=
ckable*):
bool SomeDoer::open( Door* door ) const
{
// we might need to unlock first on some cases
Lockable* lock =3D dynamic_cast<Lockable*>(door);
if ( lock !=3D NULL && lock->isLocked() && !unlock( lock ) )
{
return false;
}
return door->open();
}
Can you tell how such a situation can be resolved as elegantly without R=
TTI=
(or some self-made substitution of RTTI)?=20
The ->unlock() method becomes a no-op on a non-lockable door. In other w=
ords,
one may always call unlock, and if the door is lockable, it will be unloc=
ked;
if not, no-op.
I'm not a big fan of adding functions to interfaces for subclasses or for p=
ossibly implementable interfaces. I like the RTTI method better.
LSP is just a principle and there are degrees of breaking it. This seems l=
ike a fairly reasonable one, though I might consider having a "maybe_unlock=
" function that does the casting (it's more reusable).
There's a balance here though. Just because there's a violation of LSP doe=
sn't mean the code is bad, it just means that it could be and in a specific=
way. If you suddenly needed to make some new door type that implemented a=
different interface such that this open door function no longer worked rig=
ht then you're starting to run afoul of the LSP in bad ways.
An alternative to this kind of thing is a visitor. There could be a door_o=
pener visitor that takes a lockable and a non-lockable door as parameters. =
In many cases this is a much better alternative to either using RTTI or no=
op functions in base classes that don't belong. For this simple of an issu=
e though it could be very tempting just to violate LSP and call it good. T=
he minus here is that IFF something changes you didn't think would (and thi=
s happens a LOT) then you're kind of screwing yourself by being lazy. But =
it's a balancing act.