Re: ADT and inheritance
On Nov 18, 12:37 am, Daniel Pitts
<newsgroup.spamfil...@virtualinfinity.net> wrote:
maverik wrote:
I have some class that contains only pure virtual functions
(class- interface):
class IButton {
// Contents of the class
};
So when I actually implement some type of button I do it
like this
class ImageButton : public IButton {
// Contents of the class
};
It allows me to create a container of buttons without
knowledge about button types that this container would hold:
std::vector<IButton *> m_buttons;
The problem is: when I add some specific function to the
inherited button class then I can call it only in this way:
((ImageButton *)m_buttons[i])->SetImage(...); // I know that i-th
button is typeof ImageButton
That really should be:
ImageButton* p = dynamic_cast< ImageButton* >( m_buttons[i]);
if ( p != NULL ) // special handling...
Looks ugly a little bit, isn't it?
Of course I can add this specific function to the base class
(IButton)
class IButton {
void SetImage(...) = 0;
};
but in this case IButton becomes just a bunch of methods
from different classes.
Is there a way to make it better?
Usually, the container values aren't configured after the
fact, so you'll never call SetImage on an object reference you
got from m_buttons.
std::vector<IButton *> m_buttons;
ImageButton * myButton = new ImageButton();
myButton->SetImage(...);
m_buttons.add(myButton);
IButton should contain methods that you need to support any
IButton (in Java Swing, for example, JButton has a
paintComponent method, which can be overridden by subclasses)
If you are going to cast frequently at runtime, then you've
probably got the wrong static type.
Yes. The question is: what the vector is supposed to contain.
If it's just ImageButton, then it should be
std::vector< ImageButton* >. Otherwise, users of the vector
*generally* shouldn't use parts of the interface that are unique
to ImageButton.
The one exception I can think of is if you do define an extended
button interface, e.g.:
class IExtendedButton : public IButton
{
// More pure virtual functions with additional
// functionality.
};
It's perfectly reasonable to imagine cases where you want to use
some additional features of ExtendedButton, if they are present,
and fall back to some default handling if they aren't. In such
a case, something like:
for ( std::vector< IButton* >::const_iterator
iter = m_buttons.begin() ;
iter != m_buttons.end();
++ iter ) {
IExtendedButton* extended
= dynamic_cast< IExtendedButton* >( *iter );
if ( extended != NULL ) {
// use added features...
} else {
// use default handling...
}
}
is reasonable. Extending this to a chain of else if... for
each possible type isn't, but for one, or possibly two
extensions, OK.
--
James Kanze