M
mailforpr
Is this design well-formed? It contradicts the LSP and Design by
contract anyhow. LSP tells us that "In class hierarchies, it should be
possible to treat a specialized object as if it were a base class
object."
This is the design in question:
//////////////////////// Two abstract data types:
class Document
{
public:
virtual ~Document() {}
};
class Printer
{
public:
virtual void print(Document const&) const=0;
};
//////////////////////// Documents to be printed
class TextDocument: public Document {};
class Drawing: public Document {};
//////////////////////// Derived classes contradicting LSP
class Plotter: public Printer // a Plotter prints drawings only
{
public:
void print(Document const& d) const
{
/* use danymic_cast<Drawing const&>(d) */
}
};
class LinePrinter: public Printer // a LinePrinter prints text only
{
public:
void print(Document const& d) const
{
/* use danymic_cast<TextDocument const&>(d) */
}
};
//////////////////////// test function
void test(Printer const& p)
{
TextDocument td;
p->print(td);
}
//////////////////////// end
Now, if I were to pass a Plotter printer to the test function,
Plotter:rint would throw a bad_cast exception, because it prints
drawings only.
What exactly went wrong here? Is a Plotter not a printer, after all?
(Same would happen to the LinePrinter.)
I guess Plotter is not a Printer. Well, it is, but it doesn't print
like a general "printer" (whatever that may be) anyway. So I either
remove the Printer:rint method completely and use dynamic_cast a lot
to access Plotter:rint, or I don't have Plotter inherited from
Printer (which I don't prefer, because I need a pointer pointing to
various printers).
I rather remove the Printer:rint method and use dynamic_cast a lot,
which is ugly. Because this way it still throws exceptions if 'derived'
doesn't happen to be a Printer. Either way, there's always a
dynamic_cast throwing something unpleasant, isn't it?
contract anyhow. LSP tells us that "In class hierarchies, it should be
possible to treat a specialized object as if it were a base class
object."
This is the design in question:
//////////////////////// Two abstract data types:
class Document
{
public:
virtual ~Document() {}
};
class Printer
{
public:
virtual void print(Document const&) const=0;
};
//////////////////////// Documents to be printed
class TextDocument: public Document {};
class Drawing: public Document {};
//////////////////////// Derived classes contradicting LSP
class Plotter: public Printer // a Plotter prints drawings only
{
public:
void print(Document const& d) const
{
/* use danymic_cast<Drawing const&>(d) */
}
};
class LinePrinter: public Printer // a LinePrinter prints text only
{
public:
void print(Document const& d) const
{
/* use danymic_cast<TextDocument const&>(d) */
}
};
//////////////////////// test function
void test(Printer const& p)
{
TextDocument td;
p->print(td);
}
//////////////////////// end
Now, if I were to pass a Plotter printer to the test function,
Plotter:rint would throw a bad_cast exception, because it prints
drawings only.
What exactly went wrong here? Is a Plotter not a printer, after all?
(Same would happen to the LinePrinter.)
I guess Plotter is not a Printer. Well, it is, but it doesn't print
like a general "printer" (whatever that may be) anyway. So I either
remove the Printer:rint method completely and use dynamic_cast a lot
to access Plotter:rint, or I don't have Plotter inherited from
Printer (which I don't prefer, because I need a pointer pointing to
various printers).
I rather remove the Printer:rint method and use dynamic_cast a lot,
which is ugly. Because this way it still throws exceptions if 'derived'
doesn't happen to be a Printer. Either way, there's always a
dynamic_cast throwing something unpleasant, isn't it?