Board index » cppbuilder » question concerning abstract classes

question concerning abstract classes


2006-09-23 12:17:26 AM
cppbuilder17
I would like to make the class TBaseMonitor abstract, but the children
have no common names for methods with different implementation.
Do I have to rename AddPoint and AddLine to the same name and define
this method in the base class as follows:
virtual void __fastcall AddPoint(double curDateTime) = 0; ?
Why there is no keyword like 'abstract' to define the class as abstract?
Is there a special reason to do it by this way?
What about data objects without methods (the base class defines common
fields and the children add specific fields)?
Kind regards,
Rolf
class TBaseMonitor : public TObject {
protected:
double start_;
double end_;
long i_start_;
long i_end_;
int timestep_;
public:
double __fastcall GetStart();
double __fastcall GetEnd();
void __fastcall SetStart(double startMonitor, double startSimulation,
int timestep);
void __fastcall SetEnd(double endMonitor, double endSimulation, int
timestep);
bool __fastcall InRange(long timestep);
};
class TChartMonitor : public TBaseMonitor {
protected:
TChartMonitorObjects* monitorObjects_;
public:
void __fastcall CreateSeries(TChart* Chart);
void __fastcall DeleteSeries();
void __fastcall AddPoint(double curDateTime);
};
class TFileMonitor : public TBaseMonitor {
protected:
TFileMonitorObjects* monitorObjects_;
public:
void __fastcall OpenStream(const AnsiString filename);
void __fastcall CloseStream();
void __fastcall AddLine(double curDateTime);
};
 
 

Re:question concerning abstract classes

Rolf Fankhauser < XXXX@XXXXX.COM >writes:
Quote
I would like to make the class TBaseMonitor abstract, but the
children have no common names for methods with different
implementation. Do I have to rename AddPoint and AddLine to the
same name and define this method in the base class as follows:

virtual void __fastcall AddPoint(double curDateTime) = 0; ?
I doubt it, but it's hard to tell.
Unless there is a client who has a reference (or pointer) TBaseMonitor
and might want to call AddPoint if the reference refers to a
TChartMonitor object and AddLine() if the reference refers to a
TFileMonitor object?
But if such a client doesn't exist, it's questionable whether the
entire class hierarchy makes sense.
Please provide some more information about the responsibilities of the
three classes and how they are going to be used.
Quote
Why there is no keyword like 'abstract' to define the class as
abstract?
C++ already has many keywords. What benefit would adding this one
bring us? You can simply make a virtual member function pure virtual,
and the class is abstract.
Quote
Is there a special reason to do it by this way?
What way?
Quote
What about data objects without methods (the base class defines
common fields and the children add specific fields)?
Usually nobody cares whether the base class of such a hierarchy is
abstract.
 

Re:question concerning abstract classes

"Rolf Fankhauser" < XXXX@XXXXX.COM >wrote in message
Quote
I would like to make the class TBaseMonitor abstract, but the
children have no common names for methods with different
implementation.
Then why do you want to make an abstract base class? Such things allow
you to treat a class hierarchy like one "generic" type of object. At
the abstract level, all the objects in the hierarchy can be treated as
if they are instances of the base class, and thus need to appear
homogeneous at this level. If the derived classes need to include more
than one instance of the base, you can use virtual inheritance, but
that is a different concept.
--
Bruce
 

{smallsort}

Re:question concerning abstract classes

Rolf Fankhauser < XXXX@XXXXX.COM >writes:
Quote
I would like to make the class TBaseMonitor abstract, but the
children have no common names for methods with different
implementation.
What, then, is the base class abstracting?
Quote
Do I have to rename AddPoint and AddLine to the same name and define
this method in the base class as follows:

virtual void __fastcall AddPoint(double curDateTime) = 0; ?
I'd argue that inheritance is the wrong solution to this problem. The
whole point of polymorphism is abstraction, such that clients work
with the abstract interface and do not care what type of object is
actually implementing it.
To have derived classes with different named functions would require
that callers be fully aware of the actual object that is being used to
implement the interface.
Alternately, if you want to shoe-horn the derived classes to fit the
base interface, you could implement the virtual function in the
derived class that "forwards" the call into another function with
another name.
But if the derived classes really are not fully substitutable for the
base, think hard about changing your design.
Quote
Why there is no keyword like 'abstract' to define the class as
abstract? Is there a special reason to do it by this way?
There aren't keywords to do a lot of things. But you can make classes
abstract easily enough without one. No big deal.
Quote
What about data objects without methods (the base class defines common
fields and the children add specific fields)?
Not a good idea. Protected data is a form of broken encapsulation.
It makes the data become part of the object's interface, and assumes
all derived types actually need that data. If they do, a protected
interface could provide accessors to the private data.
--
Chris (TeamB);
 

Re:question concerning abstract classes

Rolf Fankhauser < XXXX@XXXXX.COM >writes:
Quote
Thomas Maeder [TeamB] wrote:

>Please provide some more information about the responsibilities of
>the
>three classes and how they are going to be used.
>

They are used to manage the output of values that are calculated at
each time step by a simulation program. The time step is 10 min and
the time period normally 10 years or more. So, the number of time
steps is in the order of 500'000 or more. The user can choose which
values are added to time series in a chart (TChartMonitor) or saved to
a file (TFileMonitor). He can also define start and end time of values
be saved in the chart or file. The simulation program would normally
generate a instance of TChartMonitor and one of TFileMonitor.
Does that mean that TBaseMonitor contains just the stuff common to
TChartMonitor and TFileMonitor?
Quote
First I intended to add boolean properties to the elements which
calculate the values like:

bool SaveQtoChart;
bool SaveQtoFile;

but I think that the concept with monitor objects is more flexible. In
a next step I can implement that user can generate as many charts as
they want and define the values to be shown for each chart separately.

But there is no reason to generate an instance of TBaseMonitor, so I
thought I make it abstract to avoid creation by mistake. Is this not
common practice?
It is common practice in clase hierarchies that make sense. I am not
(yet?) convinced that yours makes sense. It may well make sense; I
just haven't seen why so far.
Quote
Because TChartMonitor and TFileMonitor have some common parts, I
introduced the hierarchy. Otherwise I would have some dublicated code.
This answers my question from above.
Inheritance is very often not the right approach when the problem is
to avoid duplicated code. The main reason is that inheritance is the
strongest coupling that two classes can have; to get a flexible
system, a good design usually aims at having just enough coupling
between classes, but not more.
Would renaming TBaseMonitor to something more appropriate and chaging
your class relationships to composition (a relationship with weaker
coupling) work as well?
I.e.:
class TFormerlyKnownAsBaseMonitor
{
public:
double GetStart() const;
double GetEnd() const;
void SetStart(double startMonitor,
double startSimulation,
int timestep);
void SetEnd(double endMonitor,
double endSimulation,
int timestep);
bool InRange(long timestep) const;
private:
double start_;
double end_;
long i_start_;
long i_end_;
int timestep_;
};
class TChartMonitor
{
public:
void __fastcall CreateSeries(TChart* Chart);
void __fastcall DeleteSeries();
void __fastcall AddPoint(double curDateTime);
private:
TFormerlyKnownAsBaseMonitor commonStuff_;
TChartMonitorObjects* monitorObjects_;
};
I'm sure that you'll find better names than
TFormerlyKnownAsBaseMonitor and commonStuff_.
[Note that I declared some member functions const and some data mebers
private on my way.]
If my suggestion doesn't work, please explain why. This will probably
be the answer to Chris Uzdavinis's question: "What is the base class
abstracting?"
 

Re:question concerning abstract classes

Thomas Maeder [TeamB] wrote:
Quote

Please provide some more information about the responsibilities of the
three classes and how they are going to be used.

They are used to manage the output of values that are calculated at each
time step by a simulation program. The time step is 10 min and the time
period normally 10 years or more. So, the number of time steps is in the
order of 500'000 or more. The user can choose which values are added to
time series in a chart (TChartMonitor) or saved to a file
(TFileMonitor). He can also define start and end time of values be saved
in the chart or file. The simulation program would normally generate a
instance of TChartMonitor and one of TFileMonitor.
First I intended to add boolean properties to the elements which
calculate the values like:
bool SaveQtoChart;
bool SaveQtoFile;
but I think that the concept with monitor objects is more flexible. In a
next step I can implement that user can generate as many charts as they
want and define the values to be shown for each chart separately.
But there is no reason to generate an instance of TBaseMonitor, so I
thought I make it abstract to avoid creation by mistake. Is this not
common practice?
Because TChartMonitor and TFileMonitor have some common parts, I
introduced the hierarchy. Otherwise I would have some dublicated code.
I renamed the AddLine to AddPoint in TFileMonitor and defined AddPoint
in TBaseMonitor as virtual. That works fine and the compiler complains
if I try to create an instance of TBaseMonitor.
 

Re:question concerning abstract classes

Chris Uzdavinis (TeamB) wrote:
Quote
I'd argue that inheritance is the wrong solution to this problem. The
whole point of polymorphism is abstraction, such that clients work
with the abstract interface and do not care what type of object is
actually implementing it.

To have derived classes with different named functions would require
that callers be fully aware of the actual object that is being used to
implement the interface.
They are aware of the actual object! I used inheritance to avoid
dublicating code (properties and methods) which is equal for the derived
classes.
Quote

Alternately, if you want to shoe-horn the derived classes to fit the
base interface, you could implement the virtual function in the
derived class that "forwards" the call into another function with
another name.

But if the derived classes really are not fully substitutable for the
base, think hard about changing your design.
Yes, Thomas proposed a composition design. I think that's more
appropriate for my problem.
Please find details in Thomas posts and my answers to them.
Quote
>What about data objects without methods (the base class defines common
>fields and the children add specific fields)?


Not a good idea. Protected data is a form of broken encapsulation.
It makes the data become part of the object's interface, and assumes
all derived types actually need that data. If they do, a protected
interface could provide accessors to the private data.
Ok, I aggree.
 

Re:question concerning abstract classes

Rolf Fankhauser < XXXX@XXXXX.COM >writes:
Quote
But if commonStuff_ is private, how can I access the public members
of TFormerlyKnownAsBaseMonitor?

I must surface them to TChartMonitor:

public:
void SetStart(double startMonitor, double startSimulation, int
timestep);
I see. So the two monitor classes share interface as well.
Please show some code where these monitor classes are used, i.e. which
member functions are called by whom, who creates monitor objects
etc.. Otherwise it is difficult to give you good advice.
 

Re:question concerning abstract classes

Thomas Maeder [TeamB] wrote:
Quote
Inheritance is very often not the right approach when the problem is
to avoid duplicated code. The main reason is that inheritance is the
strongest coupling that two classes can have; to get a flexible
system, a good design usually aims at having just enough coupling
between classes, but not more.

Would renaming TBaseMonitor to something more appropriate and chaging
your class relationships to composition (a relationship with weaker
coupling) work as well?

I.e.:

class TFormerlyKnownAsBaseMonitor
{
public:
double GetStart() const;
double GetEnd() const;

void SetStart(double startMonitor,
double startSimulation,
int timestep);
void SetEnd(double endMonitor,
double endSimulation,
int timestep);

bool InRange(long timestep) const;

private:
double start_;
double end_;
long i_start_;
long i_end_;
int timestep_;
};

class TChartMonitor
{

public:
void __fastcall CreateSeries(TChart* Chart);
void __fastcall DeleteSeries();
void __fastcall AddPoint(double curDateTime);

private:
TFormerlyKnownAsBaseMonitor commonStuff_;

TChartMonitorObjects* monitorObjects_;
};

I'm sure that you'll find better names than
TFormerlyKnownAsBaseMonitor and commonStuff_.

[Note that I declared some member functions const and some data mebers
private on my way.]
const is ok. I changed that too. But if commonStuff_ is private, how can
I access the public members of TFormerlyKnownAsBaseMonitor? I must
surface them to TChartMonitor:
public:
void SetStart(double startMonitor, double startSimulation, int
timestep);
void TChartMonitor::SetStart(double startMonitor, double
startSimulation, int timestep)
{
commonStuff_.SetStart(startMonitor, startSimulation, timestep);
}
But this 'surfacing' must be also done for TFileMonitor. Dublicate code
again!
Another solution would be to define a public accessor for commonStuff_
CommonStuff() but the call of SetStart would not be very nice:
ChartMonitor->CommonStuff->SetStart(...)
Quote
If my suggestion doesn't work, please explain why. This will probably
be the answer to Chris Uzdavinis's question: "What is the base class
abstracting?"
Your suggestion works but at the moment I don't see what I 'loose' if I
use inheritance (without setting the base class abstract). It seems to
be more easier to implement and use than your proposed composition.
As you said above composition is more flexible than inheritance. I also
read this in 'Design Patterns'. I must believe it because I have not
enough experience with OO design.