Henri once suggested making the shader_backend_t structure a COM object, that is created and destroyed by the device. That would make the state of the data it manages clearer(belongs to the shader object), though it would add some stuff we don't need, like the IUnknown parts, refcounting. If we did that we could call the "shader function routing" "inheritance" and are well within OOP slang again.
Yes, what you are doing is exactly inheritance - whether it's done through COM or not doesn't really matter.
However, since there are 3 base things to inherit from (arb, glsl, none), you're inheriting each of them and now you have 6 "backends". It seems that the base functionality is fairly independent of the derived functionality, so that's why I suggested composition over inheritance here. I understand you're concerned with linking vertex and fragment together - but that should probably go in a separate object.
My concern is that if we break up the shader structure into multiple objects(e.g. vertex shader handler, pixel shader handler, fixed function vertex replacement, fixed function pipeline replacement, depth blit handler, pipeline linker), then we'll get simple single objects, but the putting these parts together adds more complexity than we save in the first place. Often in OOP programs(and other paradigms as well) you don't know what one component does without knowing the whole program.
Sure, there are always tradeoffs - it's your call, I'm just offering a semi-informed opinion :)
I'm sure any approach will be successful in the end, but it will be interesting to see how code that's written now scales to GL3, D3D10, geometry shaders, and upcoming extensions. In that respect, it seems like a good idea to try an ATIfs backend now as a test of the underlying framework.
Ivan