Reputation: 1485
I think my mind is fried at this point and I am looking for some help as to how to connect the following concern-oriented classes in C++.
SensorBase:
contains a typical sensors functionality. most of the sensors share the same functionality, but some of the functions are dependent on each specific sensor class and are therefore declared "virtual" (fe SensorBase::calcFactor()
and SensorBase::calcCelling()
).
SensorThreshold & SensorTrend: these classes extend the functionality of just specific bits of the SensorBase class depending on whether I want to track the current sensor reading against a "threshold level", or whether I want to track the trend of a sequence of sensor readings. They both implement differently "calcFactor()". It makes absolute sense that these classes are derived from SensorBase.
Finally, my mix up happens here: CO2Sensor, NH3Sensor, O2Sensor, etc: These are "Xgas" sensor class (will be called XSensor as a group from now on). For each sensor I may need to track the threshold, or the trend of the acquired values, or both. This statement suggests that I could declare one (or both) SensorThreshold / SensorTrend objects.
The problem (and twist) is that each XSsensor needs to redefine the SensorBase::calcCelling() function. So thinking it like this it seems that deriving XGasSensor from either SensorThreshold , or SensorTrend (as public virtual to avoid the "diamond problem") would help. But then I do not know which of SensorThreshold ::calcCelling() and SensorTrend::calcCelling() would be called. The 2 have identical implementations, but may be called with a different value as param.
If I am not mistaken, the compiler should throw an error here and abort compilation. But then, I am left with no way to implement calcCelling() from each XGasSensor.
The above is wrapped up in the following
class SensorBase
{
public:
virtual calcFactor();
virtual calcCelling();
};
class SensorThreshold : virtual public SensorBase
{
public:
calcFactor();
calcCelling();
};
class SensorTrend : virtual public SensorBase
{
public:
calcFactor();
calcCelling();
};
Then either
class CO2Sensor
{
public:
SensorThreshold sensorThres;
SensorTrend sensorTrend;
//but I cannot implement calcCelling() now
};
or
class CO2Sensor: public SensorThreshold , public SensorTrend ;
{
public:
calcCeilling(); //this would probably be "ambigious" error by the compiler
};
In the end I guess the question is: how can I implement bits of SensorBase in SensorThreshold & SensorTrend and other bits in each of XGasSensor? and at the same time base my XGasSensor implementation to either SensorThreshold or SensorTrend or both?
EDIT:
The above may make a little bit more sense if I say that currently SensorThreshold and SensorTrend functionality (explained below) is part of the SensorBase class. So all XGasSensors (explained later on as well) derive the SensorBase and implement calcCeiling()
. This way, all sensors keep track of both Thresholds and Trends and this is not ideal (as not all sensors need both Threshold tracking and trend tracking). This is why i am attempting to separate the threshold related functionality from the trend related one.
Upvotes: 1
Views: 128
Reputation: 1499
Without overriding calcCeiling()
in XSensor
, you will get an ambiguity error if you attempt to call this method on an XSensor
. However, you can call you can call either version of this method from SensorThreshold
or SensorTrend
by just qualifying it. If you override calcCeiling()
in XSensor
calls to this will be unambiguous for XSensor
class CO2Sensor: public SensorThreshold , public SensorTrend
{
public:
int calcCeiling() override {
SensorThreshold::calcCeiling(); // this works
SensorTrend::calcCeiling(); // this also works
}
};
// by another object.
SensorBase* co2sensor = CreateSensor("CO2");
co2sensor->SensorThreshold::calcCeiling(); // non-ambiguous.
co2sensor->SensorTrend::calcCeiling(); // non-ambiguous.
co2sensor->calcCeiling(); // non-ambiguous (calls CO2Sensor::calcCeiling.)
I'd reconsider your inheritance model because it sounds like you're trying to add additional capabilities onto a sensor, which sounds better portrayed as a decorator pattern than multiple inheritance.
Upvotes: 1
Reputation: 4855
class SensorBase
{
public:
virtual calcFactor();
virtual calcCelling();
};
class SensorThreshold : virtual public SensorBase
{
public:
calcFactor();
Virtual calcCelling()
{ThCeiling()}
Protected:
Virtual ThCeiling();
};
class SensorTrend : virtual public SensorBase
{
public:
calcFactor();
Virtual calcCelling()
{TrCeiling();}
Protected:
Virtual TrCeiling();
};
class CO2Sensor: public SensorThreshold , public SensorTrend ;
{
Protected:
TrCeiling();
ThCeiling();
};
Upvotes: 1
Reputation: 357
I believe you are saying that the CO2 sensor could implement either the Threshold or Trend functionality and that would be determined at run time when such a CO2 sensor would be created.
Therefore I would suggest an approach where the CO2 sensor would contain a pointer to the base class, which could be initialized, perhaps upon construction.
class CO2Sensor {
private:
SensorBase *sensorFunctionality;
public:
CO2Sensor( SensorBase *functionality);
returnType calcCeiling() { return functionality->calcCeiling(); }
}
The constructor body would assign the functionality
argument to the sensorFunctionality
data member
It if were the case that many sensor has this multiple functionality behavior you might have a class called MultifunctionSensor, that does this dispatching and then have all MultifunctionSensor classes derive from it.
Upvotes: 0