Just because a method is virtual doesn't mean there's no implementation behind it. The PIDController::GetError() method has a definition behind it.
Code:
/**
* Returns the current difference of the input from the setpoint
* @return the current error
*/
float PIDController::GetError() const {
double pidInput;
{
std::lock_guard<priority_recursive_mutex> sync(m_mutex);
pidInput = m_pidInput->PIDGet();
}
return GetSetpoint() - pidInput;
}
The virtual keyword just ensures you get the "right" method call if you extend PIDController and want your own implementation of GetError to run. So, if you extend PIDController and make a new ShooterPIDController and you implement your own implementation of GetError() and your instance of ShooterPIDController is cast into PIDController and you call ->GetError() on that pointer you will get the ShooterPIDController::GetError implementation. If it wasn't virtual you'd get PIDController::GetError() because then the decision would be made at compile time and not runtime.
You're only forced to implement a virtual method when the base class makes it null. So something declared: virtual float GetError() = 0; would force you to actually implement it if you wanted to use it, and that would have to be in a derived class.
I do not miss C++ at all.
