Sunday, April 16, 2017

Breaking abstract class interface in C++

Today while working on some code I had the need to make a tiny-bit-small break on a contract from an abstract base class.

The case is that I had an abstract base class called Pin, that contracted 2 methods for subclasses. The problem is that the InputPin class while benefiting from other functionality provided by the class Pin, could not sensibly provide a setPinValue method. Imagine I am naive and will only inform this operation is impossible on runtime:

volatile bool pinA1 = false;

class Pin {
public:
 virtual void setPinValue(bool value) = 0;
 virtual bool getPinValue() const = 0;
 virtual ~Pin() {}
}

class InputPin : public Pin {
public:
 virtual void setPinValue(bool value) { throw std::runtime_error("Cannot set value on input pin"); }
 virtual bool getPinValue() const { return pinA1 };
}

class OutputPin : public Pin {
public:
 virtual void setPinValue(bool value) { pinA1 = true; }
 virtual bool getPinValue() const { return pinA1 };
} 

Then I set out to find if I could use the compiler for my help in such a case. As usual Stackoverflow had question and answer about it. The answered marked as right is the ideal answer: No you cannot delete Pure Virtual Methods, fix your design. A bit further down showed the real answer: You can achieve something similar but it is not advised:

class InputPin : public Pin {
public:
 virtual bool getPinValue() const { return pinA1 };
private: 
 virtual void setPinValue(bool value) { throw std::runtime_error("Cannot set value on input pin"); } 
}


Just encapsulate the breaking method in the private part of the class and no one will be able to use it. If the Older-You gets the idea of using it in some private part of your own implementation you still get the luxury of the exception

I like answers who say "You kind of can do it, but you shouldn't", because you get to learn the corner cases and tricks with which to shoot yourself in the foot some time later. I, like everyone else, like a corner trick to impress the girls. Of course some time later it bites me back, or just my Older-Me looks back with astonishment at such a pretentious idiot I was.

*EDIT* After thinking a bit more about it and talking with my friend about it, he came up with the idea that just hiding the method in a private part of the class is not enough to make it reachable. This is because if the class is called polymorphically the virtual dispatcher in run-time will still reach this hidden method.

The best way in the end is to make it private and do nothing.

TLDR; Redesign your architecture to not have broken interfaces.

No comments:

Post a Comment