@joshuahardwell,
The getPotential function works because a pointer to an object can also point to all objects derived from that object, right? |
Right. And the virtual function allows derived-class-specific functionality to be performed from a base class pointer/reference pointing/referring to an object of the derived class.
Your solution does require two separate classes, one for a pot on a mux and one for a pot by itself. And likewise, I would have to declare additional classes for any other special cases. Is this good practice for how to address this situation? |
I think it is. Inheritance makes sense when a specific class is a specialized version of a more general class. If you use the "is a" test on two classes, you can frequently find your inheritance hierarchies. Classic examples of this are:
Triangle "is a" Shape, so Triangle inherits from Shape.
Employee "is a" Person, so Employee inherits from Person.
Dog and Cat "are" Animals, so Dog and Cat inherit from Animal.
In your case, pot on a mux "is a" pot, so it makes sense for pot on a mux to derive from pot. Also, you only need to write the code that specializes the derived class. All derived class behavior that is common with the base class behavior is available automatically and does not have to be rewritten. In your example, I think the derived class will actually be very small unless you start finding a bunch of other differences between a pot and a pot on a mux.
My first intuition was to define a single potentiometer class, with a single read-function, so as to hide from the user the details of how exactly the read was occurring. So the user could simply say, "potentiometer p; p.analogRead();" |
But that's not what you were doing in the code in your first post. You were going to do this:
1 2
|
potentiometer p1(A1, analogRead); // attached to pin A1
potentiometer p2(1, aMux.AnalogRead); // attached to input 1 on aMux
|
You know ahead of time which potentiometer is on a mux, because you have to pass in the correct function. With a derived class, your equivalent code would be:
1 2
|
Potentiometer p1(A1);
MuxPotentiometer p2(1);
|
Note: I originally skipped the byte argument to the constructor to reduce confusion when discussing inheritance. Here is another iteration of my example with that argument being handled:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
class Potentiometer
{
public:
Potentiometer(byte p) : pinNum(p) {}
virtual int readAnalog() { /* do something and return an int */}
private:
byte pinNum;
};
class MuxPotentiometer : public Potentiometer
{
public:
MuxPotentiometer(byte p) : Potentiometer(p), mux(1, 2, 3, A0) {}
virtual int readAnalog() { return mux.readAnalog(); }
private:
AnalogMux mux;
};
|