Re: Why RTTI is considered as a bad design?
On Thursday, August 23, 2012 12:08:20 PM UTC-7, Leigh Johnston wrote:
On 23/08/2012 19:19, Noah Roberts wrote:
On Thursday, August 23, 2012 10:29:00 AM UTC-7, =EF=BF=BD=EF=BF=BD Tiib=
wrote:
Maybe try to pack up your words with code example?
struct lock {
virtual ~lock() {}
virtual void unlock() = 0;
virtual bool engaged() const = 0;
};
struct null_lock : lock {
void unlock() {}
bool engaged() const { return false; }
};
struct single_lock : lock {
void unlock() { state = UNLOCKED; }
bool engaged() const { return state == LOCKED; }
};
// can be added later...
struct multi_lock : lock {
// probably have this syntax wrong...
void unlock() { for ( lock & current_lock : locks) current_lock.unlo=
ck(); }
bool engaged() const {
return find_if(locks.begin(), locks.end(), bind(&lock::engaged, _1=
)) != locks.end();
}
iterator begin();
iterator end();
private:
?? locks;
};
struct door {
virtual ~door() {}
bool open() {
if (lock()->engaged()) return false;
state = OPEN;
return true;
}
lock* lock();
private:
lock my_lock;
door_state state;
};
Use code:
void go_through_door(door & entry) {
entry.lock()->unlock();
entry.open();
// go through...
}
Looks pretty darn simple to me. Compared to:
// may be a few lines of code smaller...but not much.
struct door { ... };
struct lockable { .... };
struct lockable_door : door, lockable { ... };
// but you pay for it here...
void go_through_door(door & entry) {
if (auto lock = dynamic_cast<lockable*>(&entry))
lock->unlock();
entry.open();
};
In general yes one should prefer composition over inheritance but the
proper way to do it using inheritance is really quite simple:
struct door : lockable
{
bool open()
{
if (!unlock())
return false;
}
virtual bool unlock()
{
/* ordinary doors have no locks */
return true;
}
};
As has already been discussed, having the base class contain an unlock func=
tion just so that you can call the behavior in a base class is not good des=
ign. You'll start to see the problem, perhaps, when you consider how you'd=
implement:
struct sliding_door : door { ... };
Once again, some will have locks and some won't. Going to have two classes=
for this too?? Tiib's runs into the same difficulty. It gets even worse =
when you start having many different kinds of locks and what you end up get=
ting is subclass explosion and often this comes with a lot of redundant cop=
y-pasta.
The recommended pattern to combat this sort of problem is the bridge. That=
's basically what the door->lock relation creates.