views:

117

answers:

3

I have a base class A with a constant static variable a. I need that instances of class B have a different value for the static variable a. How could this be achieved, preferably with static initialization ?

class A {
public:
    static const int a;
};
const int A::a = 1;

class B : public A {
    // ???
    // How to set *a* to a value specific to instances of class B ?
};
+4  A: 

You can't. There is one instance of the static variable that is shared by all derived classes.

anon
Yeah, just found out after posting the question. You managed to answer in the 5s after I posted the question and tried to delete the question. Deleting the question was rejected because of your response and 2 up votes :)
chmike
+3  A: 

Static members are unique in the application. There is a single A::a constant in your system. What you can do is create a B::a static constant in B that will hide the A::a static (if you don't use the fully qualified name:

class A {
public:
   static const int a = 10;
};
static const int A::a;
class B : public A {
public:
   static const int a = 20;
   static void test();
};
static const int B::a;
void B::test() {
   std::cout << a << std::endl;    // 20: B::a hides A::a
   std::cout << A::a << std::endl; // 10: fully qualified
}
David Rodríguez - dribeas
Yes I knew that. The problem is when I have a pointer like this A *p = new B. The p->test() would print 10 and 10. That is the problem I have. It seem the only way is to use a virtual method.
chmike
@chmike: If you need polymorphism (different behavior based on the actual type of the instance and not the pointer/reference) then you do need virtual methods. In the example I provided, `A *p = new B; p->test()` will not even compile since `test()` does not exist at the `A` level.
David Rodríguez - dribeas
Yes, obviously. I missed that. So the answer is to replace the static variable a with a virtual method and redefine the method in derived class. The method may contain a static local variable if it is needed. If you provide a simple code example I'll grant you the answer.
chmike
It depends on what the variable represents, it can be either a method static variable or a class static that is returned from the actual function, depending on what makes more sense.
David Rodríguez - dribeas
+2  A: 

You can do this with Curiously recurring template pattern (you'll have to lose the const though).

template <typename T>
class A {
public:
    static int a;
};

template <typename T>
int A<T>::a = 0;

class B : public A<B> {
    struct helper { // change the value for A<B>::a
        helper() { A<B>::a = 42; }
    };
    static helper h;
};
B::helper B::h;
Motti
This creates a different static variable.
anon
@Neil, Sure does, one variable can't have two different values.
Motti
The proposal of David Rodriguez is simpler. What is the benefit of using a template here ?
chmike
@chmike, I'm not sure there is a benefit to my way (I wrote it before seeing David's). David's method creates a different variable for B::a which just happens to have the same name while my method has separate variables from the start, if there are many such derived classes (and A is used only as a base) I think mine is slightly more elegant (you don't have to define the static variable over and over).
Motti