LabVIEW Object-Oriented Scripting Engine
This question is for LabVIEW 2019. Highlighting that fact first because some of the "standard" object-oriented techniques like interfaces, type inference, template specialization, etc. aren't available to me. I'm working in an established code base where there is a single base class that handles core functionality and many tiers of subclasses. Some are abstract subclasses that encapsulate core functionality for a particular family of products, and then of course there are the concrete subclasses. One responsibility of the base class is to manage a scripting engine. Methods are named in a text file to build a queue and then the base class runs those commands by reference. The problem I'm having is that the commands depend on the class type. For example, the abstract "inspection_station" class might have a command called "log_inspection_results" that is common to all inspection stations, but then a "microscope_inspection_station" would be the only class that has a "connect_to_microscope" command. What's more, some commands are overridden; in this example the inspection_station might write to a text file by default, but the microscope inspection station overrides that functionality to write a PNG instead. The problem is that it's the base class that's trying to execute the commands. This was originally handled by defining all commands at the base class level. The call is defined at the base class, but at runtime it's the concrete instance executing the command and so the active type and the resulting command specialization is automatically correct. This is great, but defining a bunch of virtual commands at the base class just pollutes the base class and adds a lot of boilerplate work to add a new command. I tried changing it such that the subclasses were responsible for tracking the commands they had available and would provide a list to the base class. The base class would invoke the commands blindly by name, but then the problem was that the base class could only hand a reference to the base class - all the subclass-specific commands needed to be restructured to take a generic base class reference and had to downcast to get the subclass-specific class data. I take frequent downcasting as a code smell, but I can't figure out a better architecture. I thought I could restructure things a bit and make the command execution virtual, with the concept that the concrete subclass could pass its own reference to any tier of parent/grandparent/etc. class, because a more specific type is always a kind of less specific type. Unfortunately LabVIEW is very picky when calling by reference and the inputs need to EXACTLY match the invoked method - I can't pass in a subclass where the method signature is expecting a parent class because the types don't exactly match. I thought I could change the structure to a visitor pattern and move the commands to their own class that accept a reference to the existing class, but here again the base class is what's going to be invoking the commands. This means a restructured command class would have to accept only a reference to the base class and then would need to do a bunch to type comparisons to figure out how to downcast, and there again is the same downcasting problem I was trying to avoid, but even worse with the type comparisons. I'm not sure if there's a pattern that I'm forgetting about or if this isn't really doable given the constraints LabVIEW is imposing.

This question is for LabVIEW 2019. Highlighting that fact first because some of the "standard" object-oriented techniques like interfaces, type inference, template specialization, etc. aren't available to me.
I'm working in an established code base where there is a single base class that handles core functionality and many tiers of subclasses. Some are abstract subclasses that encapsulate core functionality for a particular family of products, and then of course there are the concrete subclasses.
One responsibility of the base class is to manage a scripting engine. Methods are named in a text file to build a queue and then the base class runs those commands by reference.
The problem I'm having is that the commands depend on the class type. For example, the abstract "inspection_station" class might have a command called "log_inspection_results" that is common to all inspection stations, but then a "microscope_inspection_station" would be the only class that has a "connect_to_microscope" command.
What's more, some commands are overridden; in this example the inspection_station might write to a text file by default, but the microscope inspection station overrides that functionality to write a PNG instead.
The problem is that it's the base class that's trying to execute the commands. This was originally handled by defining all commands at the base class level. The call is defined at the base class, but at runtime it's the concrete instance executing the command and so the active type and the resulting command specialization is automatically correct. This is great, but defining a bunch of virtual commands at the base class just pollutes the base class and adds a lot of boilerplate work to add a new command.
I tried changing it such that the subclasses were responsible for tracking the commands they had available and would provide a list to the base class. The base class would invoke the commands blindly by name, but then the problem was that the base class could only hand a reference to the base class - all the subclass-specific commands needed to be restructured to take a generic base class reference and had to downcast to get the subclass-specific class data.
I take frequent downcasting as a code smell, but I can't figure out a better architecture. I thought I could restructure things a bit and make the command execution virtual, with the concept that the concrete subclass could pass its own reference to any tier of parent/grandparent/etc. class, because a more specific type is always a kind of less specific type. Unfortunately LabVIEW is very picky when calling by reference and the inputs need to EXACTLY match the invoked method - I can't pass in a subclass where the method signature is expecting a parent class because the types don't exactly match.
I thought I could change the structure to a visitor pattern and move the commands to their own class that accept a reference to the existing class, but here again the base class is what's going to be invoking the commands. This means a restructured command class would have to accept only a reference to the base class and then would need to do a bunch to type comparisons to figure out how to downcast, and there again is the same downcasting problem I was trying to avoid, but even worse with the type comparisons.
I'm not sure if there's a pattern that I'm forgetting about or if this isn't really doable given the constraints LabVIEW is imposing.