Search code examples
c++inheritancetypedef

How to change the type/typedef of a class member dynamicly?


Follwing Problem. I am working on a bigger c++ project. That project has a central dataClass: mal::FrameAudio and the data class looks like this:

class FrameAudio  {
 public:

  typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> pluginType;
...
const pluginType& getPlug() const;
void setPlug(const pluginType& plugin);
...

Now I want to extend some functionality of the software, which needs a different pluginType in my case I would need:

typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> pluginType;

How can I implement the new dataType without breaking the functionality of the rest of the code?

  1. Inheritance? I thought about doing something like this FrameAudioFloat: public FrameAudio. But the data storage get initialized way earlier in the software, outside of my functionality and as far as I know, when a pointer is set to the base class you can only use the overwritten functions of the derived class. So I cannot call getPlug() since it has another return type.

  2. Template? I was thinking about creating a template class? But than I saw that the code often uses the typedef of the datastorage. You will find something like this very often in the code:

    const mal::FrameAudio::pluginType& plugins = aFrame.getPlug();

I even found that typedef in member definitions of other classes. So what is the easiest way for me to extend this class with the new typedef and funcions? For now its sufficient to me if just my functionality works with the new typedef and the rest of the code still works with the old. Maybe use auto as a typedef?


Solution

  • You can not change the type of an object dynamically, C++ doesn't allow that. So much up front.

    Now, using a template is probably the right way to go. Point is, you probably can not change this while keeping the code the same, which is what you're effectively asking for. Instead, you can write similar code but with the unsigned char replaced with a float, because that doesn't touch the existing code. In order to avoid actual code duplication, creating a template is the way to go:

    template <typename scalar> class FrameAudioT
    {
        // type from the outer class used in the plugin type
        typedef Eigen::Matrix<scalar, Eigen::Dynamic, Eigen::Dynamic> pluginType;
        // ...other code...
    };
    // for compatibility with existing code:
    typedef FrameAudioT<char> FrameAudio;
    

    Start like that with the FrameAudio class. Then, pick the next class which still depends on the legacy, non-templace FrameAudio type. Once this type isn't used any more, you can remove the typedef.

    Of course, in the middle you can refactor the code. For example, if you find your code only uses a subset of the plugin's interface that doesn't depend on its first parameter, you might be able to create a pure virtual baseclass ("interface class") and use that instead. The details depend on your application, so it's hard to give definite advise.