Search code examples
c++inheritancestaticrefactoringcode-duplication

C++ Different constant member in each derived class, how to move function to remove duplication in access?


I have derived classes that differ in some constant attribute. In all derived classes, I have a function that returns attribute. Is there a way to move the get_x function into the base class to remove the duplication? I have looked in this thread and a lot of google searches but I couldn't find exactly what I want: C++ : Initializing base class constant static variable with different value in derived class?

class Derived1: public Base{
    static const attribute x = SOME_ATTRIBUTE1;
    attribute get_x(){
        return x;
    }
};

class Derived2: public Base{
    static const attribute x = SOME_ATTRIBUTE2;
    attribute get_x(){
        return x;
    }
};

I would hope that it would look something like this, but this doesn't work because x isn't defined in base. I've also tried extern, static const attribute x, etc.

class Derived1: public Base{
    static const attribute x = SOME_ATTRIBUTE1;
};

class Derived2: public Base{
    static const attribute x = SOME_ATTRIBUTE2;
};

class Base{
    attribute get_x(){
        return x;
    }
};

Thanks.


Solution

  • A bit kludgy, but you could potentially use something similar to the following to do this:

    template <attribute x> class Base
    {
        public:
            attribute get_x ( ) { return x; }
    };
    
    class Derived1 : public Base<SOME_ATTRIBUTE_1>
    {
        ...
    };
    
    class Derived2 : public Base<SOME_ATTRIBUTE_2>
    {
        ...
    };
    

    Similar to Karl's answer, but preserves the inherited/derived relationship (well, almost - see @visitor's comment below).

    On the other hand, is there a reason for not doing simple overriding? Eg:

    class Base
    {
        public:
            virtual attribute get_x ( ) = 0;
    };
    
    class Derived1 : public Base
    {
        public:
            attribute get_x ( ) { return SOME_ATTRIBUTE_1; };
    };
    
    class Derived2 : public Base
    {
        public:
            attribute get_x ( ) { return SOME_ATTRIBUTE_2; };
    };
    

    EDIT: note that the template approach can be extended to as many attributes as are required, as follows:

    template <attribute1 x, attribute2 y ...> class Base
    {
        public:
            attribute get_x ( ) { return x; }
            attribute get_y ( ) { return y; }
            ...
    };
    

    Another solution having each attribute be a property of the class could be as follows:

    class Base
    {
        public:
            Base (attribute newX) : x(newX) { }
            attribute get_x ( ) { return x; };
        protected:
            const attribute x;
    };
    
    class Derived1 : public Base
    {
        public:
            Derived1 ( ) : Base(SOME_ATTRIBUTE_1) { }
    };
    
    class Derived2 : public Base
    {
        public:
            Derived2 ( ) : Base(SOME_ATTRIBUTE_2) { }
    };
    

    Here, each Derived has a constant property that is unique to that class. You can of course drop the const if you prefer.