Search code examples
c++visual-c++inheritanceconstantsradix

C++ Constructors, Constants, Inheritance and Avoiding Repetition


so I've been learning C++ for a few weeks now but I'm having a bit of trouble:

Class Tool
{
public:
    Tool(const float maxCarried = 1):maxAmountCarried(maxCarried){}
    virtual void Use() = 0;
    /* ... */
}

Class CuttingTool: public Tool
{
public:
    CuttingTool(const float maxCarried):Tool(maxCarried){}
    virtual void Use(){ /* ... */ }
    /* ... */
}

Class Saw: public CuttingTool
{
public:
    Saw(const float maxCarried):CuttingTool(1){}
    virtual void Use(){ /* ... */ }
    /* ... */
}
Class Scissors: public Fruit
{
public:
    Scissors(const float maxCarried):CuttingTool(2){}
    virtual void Use(){ /* ... */ }
    /* ... */
}

A few things to note:

  • I'm trying to make a big database of 'Tools'.
  • I never change the value of 'maxAmountCarried' so I've set it to const.
  • Memory/performance is important because I have a huge vector of Tools.

The problem lies within the fact that I have to keep writing:

ClassName(const float maxCarried):BaseClass(maxCarried){}

It's really tedious, moreover, I worry that if I were to add a new const value I would have to repeat the process all over again (problem when you have 50 classes inheriting from Food :S).

I feel as though I've designed this poorly. Is there a way to avoid repeating the same line of code over and over again or do I just have to suck it up and deal with it?

Thanks in advance.


Solution

  • If your only concern is the repeating initialization list you could use a macro like this:

    #define DEFAULT_CONSTRUCTOR(Child, Parent) Child(float max) : Parent(max) {}
    

    and use it like so:

    class Saw : public CuttingTool
    {
    public:
        DEFAULT_CONSTRUCTOR(Saw, CuttingTool) {}
    };
    

    You can extend this idea and do something like that:

    #define BEGIN_CLASS(Child, Parent) class Child : public Parent { \
                                          public: \
                                             Child(float max) : Parent(max) {}
    
    #define END_CLASS };
    

    and declare your classes:

    BEGIN_CLASS(Scissors, Tool)
       void cut_through_paper() {}   // specific method for scissors
    END_CLASS
    

    Note that there is no point of using const float as a parameter since you can't change arguments passed by value anyway. You might however want to use const float& to pass an argument by reference, and that will make sense if size of float is bigger than the size of a pointer in your specific platform.

    If you never change you max value, you can make it static and share it between all tool instances:

    class Tool
    {
    protected:
       static const float _max;
    public:
       Tool() {}
    };
    const float Tool::_max = 0;
    

    If you'd like to be able to change max value only once (say at the begining of your program, you can add a static function:

    static void globalMax(float max) { Tool::_max = max; }
    

    and use it where appropriate:

    int main() {
       Tool::globalMax(5);
       ...
       ...
    }
    

    Note that you should remove the const from the _max declaration.

    Finally, if performance is an issue, you probably need to rethink your design and maybe go with something else (templates maybe?)

    Hope that helps!