3

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.

Community
  • 1
  • 1
AWU
  • 33
  • 1
  • 4
  • You might be able to get away with something like a constant pointer. That can be instantiated in derived classes irc.. – alexcepoi Feb 23 '11 at 04:13

3 Answers3

2

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.

Mac
  • 14,615
  • 9
  • 62
  • 80
  • 1
    Although it is not entirely clear from the question, it seems Derived1 and Derived2 are supposed to be inherited from the *same* base class. - I see nothing wrong with the second snippet. – visitor Feb 23 '11 at 10:08
  • @visitor: true, I hadn't really thought through that `Base` and `Base` are actually different classes. Blame it on usually avoiding template programming as much as possible. That said, IIRC something more suitable might be achievable through virtual inheritance with the template virtually inheriting from a separate `Base` class. Maybe. – Mac Feb 23 '11 at 10:14
  • Hi, thanks for the solutions. The first one would be good if I only had one attribute, and the second one would be useful generally. I just thought that the attributes should be members (because they are some property of the class), but probably not much else can be done? Thanks! – AWU Feb 24 '11 at 04:44
  • @AWU: the template approach *can* be extended to further attributes, and your other comment inspired me to another option where each class does sort of own its own `attribute` as a property. See my above edit. – Mac Feb 24 '11 at 05:14
  • Thanks! I didn't know the templates can be like that. These are great answers! – AWU Feb 24 '11 at 16:56
  • I try to avoid inheritance as much as possible. If you were needing to make use of run-time polymorphism with Derived1 and Derived2, you can probably use a template function/class for that as well. There may be a learning curve, but the resulting code will be more efficient. – jbo5112 Apr 23 '13 at 16:49
1

Well, depending on what the rest of the class looks like, it might be a good use case for a template instead of polymorphic inheritance:

template <attribute X>
class Base{
    attribute get_x(){
        return X;
    }
}

typedef Base<SOME_ATTRIBUTE1> Derived1;
typedef Base<SOME_ATTRIBUTE2> Derived2;
Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
  • I think the OP's usage of the term "derived" suggests the classes in question should share a common base class, where the `get_x` method is to be moved to. BTW, calling a template class `Base` and calling instantiations of it `Derived` is a little confusing. – jon hanson Feb 23 '11 at 15:59
1
#include <iostream>
#include <typeinfo>

enum attribute {SOME_ATTRIBUTE1, SOME_ATTRIBUTE2};

class Base
{
public:
    virtual attribute get_x() = 0;
};

template <attribute Attr>
class Derived : public Base
{
public:
    virtual attribute get_x() {return Attr;}
};

typedef Derived<SOME_ATTRIBUTE1> Derived1;
typedef Derived<SOME_ATTRIBUTE2> Derived2;

int main()
{
    std::cout << typeid(Derived1().get_x()).name() << '\n';
    return 0;
}
sbi
  • 219,715
  • 46
  • 258
  • 445
  • @ltjax: See the modified code. This compiles with VC9 and outputs `enum attribute`. Is there anything I'm missing? – sbi Feb 23 '11 at 17:55
  • yea, I think I was off on that one. only 'integral' types can be template parameters, so both integers and enums work. User-defined structs won't tho. – ltjax Feb 24 '11 at 10:25